フォーム送信を制御する

このレッスンで分かること

  • submit はボタンではなく form 要素で起きるイベントです
  • 既定の動きはページの再読み込みで、放っておくと入力が消えます
  • event.preventDefault() で既定の動きを止め、JavaScript 側に処理を渡せます

フォーム送信を制御する とは

submit イベントを受け取り、ブラウザの既定の送信動作を止めて自分で処理することです。

送信ボタンを押すと何が起きているか

お問い合わせフォームの送信ボタンを押してみてください。一瞬画面が白くなり、入力していた文字がすべて消えたはずです。エラーではありません。ブラウザが決められたとおりに動いた結果です。

form 要素には、生まれつきの役割があります。中の入力内容をまとめてサーバーへ送り、返ってきた新しいページを表示する、という役割です。送り先は action 属性で指定しますが、書かなければ自分自身のページに送ります。だから同じページが読み込み直され、JavaScript も最初から走り直し、入力欄は空に戻ります。

これはインターネットの初期からある正しい仕組みです。ただ、いまのページで入力チェックをしたり、その場に結果を出したりしたいときには邪魔になります。送る前に止めて、こちらで面倒を見たいのです。

ページが再読み込みされると、変数もイベントの登録もすべて作り直しになります。前回までに書いた文字数カウンターの表示も消えます。「押したら全部リセットされてしまう」という症状を見たら、まずここを疑ってください。

submit は form で起きる

まず登録する相手を間違えないことです。押されるのはボタンですが、イベントが起きるのは form です。

const contactForm = document.querySelector(".contact-form"); contactForm.addEventListener("submit", function (event) { event.preventDefault(); formMessage.textContent = "送信を受け付けました"; });

ボタンの click で受けるやり方も一応は動きますが、すすめられません。フォームは入力欄で Enter キーを押しても送信されるからです。click で受けていると、Enter で送られたときだけ素通りしてしまいます。submit で受ければ、押しても打っても同じ入口を通ります。

受ける場所拾えるもの抜けるもの
button の clickボタンを押したとき入力欄での Enter 送信
form の submit押したときも Enter のときもなし

preventDefault で既定の動きを止める

event.preventDefault() は、そのイベントに用意されているブラウザの既定の動きを取り消すメソッドです。名前のとおり「既定の動きを、あらかじめ防ぐ」という意味です。event オブジェクトが持っているので、引数を受け取っていないと呼べません。前回まで「要らなければ書かなくてよい」と言っていた event が、ここでは必須になります。

既定の動きを持つのは submit だけではありません。

  • a 要素の click … リンク先へ移動する
  • formsubmit … 入力内容を送ってページを読み込み直す
  • 右クリック … ブラウザのメニューを出す

どれも preventDefault() で止められます。止めたうえで自分の処理を書く、という形はイベント処理の定番です。

大事なのは、書く場所です。処理の中の先頭近くに置いてください。途中でエラーが起きて preventDefault() の行まで届かないと、ページはそのまま送信されてしまいます。何が起きたのか分かりにくい不具合になるので、まず止める、それから考える、の順にします。

contactForm.addEventListener("submit", function (event) { event.preventDefault(); // まず止める // 止めたあとに、好きなだけ処理を書く });

return false で止まると書かれた古い記事がありますが、あれは onsubmit 属性の書き方の話です。addEventListener で登録した関数の中では効きません。preventDefault() を使ってください。

ブラウザ側の検証もある

input 要素には requiredtype="email" といった属性があり、これだけでブラウザが簡単な検証をしてくれます。空のまま送ろうとすると吹き出しが出て、送信そのものが行われません。この検証は submit イベントより前に走るので、通らなければ処理の関数は呼ばれません。

手軽ですが、吹き出しの文言や見た目はブラウザごとに違い、こちらでは細かく決められません。デザインをそろえたい画面では、formnovalidate を付けてブラウザの検証を切り、すべて JavaScript 側で行う作りにすることもあります。

やり方手間見た目の自由度
required などの属性だけほとんどないブラウザまかせ
JavaScript で検証書く量は増える自由に決められる
両方使う中くらい属性を土台にして補える

入門のうちは、まず JavaScript で書けるようになっておくのがおすすめです。属性でできることは、あとから足せます。

止めたあとに何をするか

止めるだけでは、押しても何も起きないページになってしまいます。見ている人は「壊れているのかな」と思います。止めたら必ず、代わりの反応を返します。今回はメッセージを 1 行出すところまでにしますが、実際の現場では次のような流れになります。

  1. preventDefault() で止める
  2. 入力内容を value で読み取る
  3. 未入力や形式のおかしいものがないか調べる
  4. 問題なければ通信で送り、結果に応じた表示を出す

3 の入力チェックは、この章の最後の回で書きます。今回はその手前まで、つまり「止めて、受け付けたと表示する」ところまでを完成させます。

止めたあとに画面をそのまま使い続けられるのが、この書き方の大きな利点です。ページが変わらないので、入力した内容も、前の回で書いた文字数の表示も残ります。送信のたびに真っ白になって最初からやり直し、という体験を避けられます。いま多くの Web サービスで、送信してもページが切り替わらないのは、どれもこの preventDefault() が土台にあるからです。

もう一点、止めたことを見ている人に必ず伝えてください。押しても何も変わらない画面は、動いていないのか受け付けられたのか区別が付きません。メッセージを 1 行出す、ボタンの文字を変える、読み込み中の表示を出す。どれでもかまわないので、押した手応えを返すようにします。

今回書くこと

お問い合わせのフォームの中、送信ボタンの下に id="form-message" の空の段落を足します。JavaScript では .contact-formsubmit イベントを登録し、処理の先頭で event.preventDefault() を呼びます。そのあと段落に 送信を受け付けました と表示します。

うまく書けていれば、送信ボタンを押しても画面は白くならず、入力した文字も残ったままメッセージだけが増えます。文字が消えてしまうなら、止められていないということです。

よくある間違い

ボタンに登録してしまう

document.querySelector(".submit-button").addEventListener("submit", handler);

button では submit は起きません。登録する相手は form です。

引数を受け取っていない

contactForm.addEventListener("submit", function () { event.preventDefault(); });

event is not defined で止まり、止められないまま送信されます。関数の丸かっこに event と書き足します。

丸かっこを付け忘れる

event.preventDefault;

これは関数を参照しただけで、呼んでいません。エラーも出ないので気付きにくく、ページだけが再読み込みされます。event.preventDefault() と書きます。

課題

  1. HTML の .contact-form の中、送信ボタンのすぐ下に id="form-message" の空の p を足す
  2. JavaScript で .contact-formsubmit イベントを登録する
  3. 処理の引数に event を受け取り、いちばん先頭で event.preventDefault() を呼ぶ
  4. そのあと #form-message に「送信を受け付けました」と表示する

ヒント

index.html
style.css
script.js
プレビュー

できているか

  • お問い合わせフォームがある
  • #form-message の段落がある
  • #form-message がフォームの中にある
  • 送信しても再読み込みされず、メッセージが残る