JavaScript | DOM 操作:フォーム操作 – フォーム送信イベント

JavaScript JavaScript
スポンサーリンク

フォーム送信イベントとは何か

フォーム送信イベントは、ユーザーがフォームを送ろうとした瞬間に発火する “submit” イベントのことです。ここが重要です:submit は「実際の送信前」に発火するため、検証や送信のキャンセル、AJAX 送信への置き換えができます。送信を止めるには e.preventDefault()、ブラウザの組み込み検証を活かすなら checkValidity() と requestSubmit() の使い分けが鍵になります。


送信イベントの基本(submit の監視とキャンセル)

最小の監視とキャンセル

<form id="f">
  <input name="email" type="email" required>
  <button>送信</button>
</form>
<script>
  f.addEventListener("submit", (e) => {
    e.preventDefault(); // 実際の送信を止める
    console.log("送信前に介入できます");
  });
</script>
HTML

ここが重要です:submit はフォーム全体に対して一回発火します。preventDefault() を呼ぶと、ブラウザによるページ遷移や HTTP 送信を止めて、独自処理(検証・AJAX)へ置き換えられます。

Enter キーやボタンでの送信

<form id="f">
  <input name="q" placeholder="検索"> <!-- フォーカス中に Enter で送信 -->
  <button type="submit">送信</button> <!-- 明示的に送信 -->
</form>
HTML

ここが重要です:入力中の Enter、type=”submit” のボタン、またはフォーム内で唯一のボタンが “送信トリガー” になります。submit の扱いは同じなので、イベント一箇所で統制できます。


組み込み検証とイベントの順序(checkValidity と requestSubmit)

組み込み検証を使う送信

<form id="f">
  <input name="email" type="email" required>
  <button type="submit">送信</button>
</form>
<script>
  f.addEventListener("submit", (e) => {
    if (!f.checkValidity()) {
      e.preventDefault(); // エラーがあれば送信を止める
      // ブラウザがバブルのエラー表示を行う(typeやrequiredに基づく)
      return;
    }
    // ここまで来たら入力は妥当
  });
</script>
HTML

ここが重要です:checkValidity() は HTML 属性にもとづく検証(required、type、min/max、pattern 等)を実行します。失敗時に preventDefault で止めるのが定石。成功時だけ送信や AJAX へ進みます。

プログラムから“検証して送信”する

<script>
  // ボタンや別UIから送信したいとき
  if (f.reportValidity()) { // 画面に検証メッセージも表示
    f.requestSubmit();      // ネイティブの送信を起動(submitが発火)
  }
</script>
HTML

ここが重要です:requestSubmit() は「送信ボタンを押したのと同じ」扱いになり、検証を通した上で submit が発火します。f.submit() は検証をスキップして即送信するので、通常は使いません(誤送信の原因になります)。


AJAX 送信に置き換える(FormData と fetch)

送信を止めて非同期送信する基本形

<form id="f" action="/api/submit" method="post">
  <input name="email" type="email" required>
  <input name="name" required>
  <button>送信</button>
</form>
<script>
  f.addEventListener("submit", async (e) => {
    e.preventDefault();               // ページ遷移を止める
    if (!f.checkValidity()) return;   // 検証NGなら何もしない

    const fd = new FormData(f);       // name→value のペアを収集
    const res = await fetch(f.action, {
      method: f.method,
      body: fd,
    });

    if (res.ok) {
      alert("送信に成功しました");
      f.reset();
    } else {
      alert("送信に失敗しました");
    }
  });
</script>
HTML

ここが重要です:FormData は実送信と同じ形で値を集め、ファイルもそのまま送れます。成功時に reset で初期化するか、エラー時はメッセージとフォーカス誘導で再入力を助けます。

JSON 送信が必要な場合

<script>
  f.addEventListener("submit", async (e) => {
    e.preventDefault();
    if (!f.checkValidity()) return;

    const data = Object.fromEntries(new FormData(f));
    const res = await fetch("/api/submit-json", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(data),
    });
    // 後続は前例と同様
  });
</script>
HTML

ここが重要です:API が JSON を期待するなら、FormData をオブジェクト化して JSON 化します。checkbox の未チェックはキーなし(存在しない)になるため、必要なら明示的に false を補完する設計にしましょう。


どのボタンが押されたかを知る(submitter の活用)

複数の送信ボタンを区別する

<form id="f">
  <button name="action" value="save">保存</button>
  <button name="action" value="delete">削除</button>
</form>
<script>
  f.addEventListener("submit", (e) => {
    const btn = e.submitter; // 押されたボタン(対応ブラウザ)
    const action = btn?.value || "save";
    e.preventDefault();
    console.log("押されたアクション:", action);
  });
</script>
HTML

ここが重要です:submitter で「どのボタンが送信を起動したか」が分かります。対応が必要な環境では、クリック時に外部変数へ退避してから submit 内で参照する方法でも同じことができます。


よく使う補助テクニック(フォーカス、エラー表示、進行中のブロック)

エラー時はフォーカスを当てて再入力を助ける

<script>
  f.addEventListener("submit", (e) => {
    if (!f.checkValidity()) {
      e.preventDefault();
      const firstInvalid = f.querySelector(":invalid");
      firstInvalid?.focus();
    }
  });
</script>
HTML

ここが重要です:最初のエラー要素へ focus() を合わせるだけで、学習負担が大きく下がります。ネイティブ検証と組み合わせると効果的です。

二重送信の防止(押してから完了まで無効化)

<script>
  f.addEventListener("submit", async (e) => {
    e.preventDefault();
    if (!f.checkValidity()) return;

    const btn = e.submitter;
    btn.disabled = true;
    try {
      // fetch などの送信
    } finally {
      btn.disabled = false;
    }
  });
</script>
HTML

ここが重要です:送信中にボタンを無効化すると、連打や二重送信を防げます。UI 上はローディング表示と組み合わせるとさらに親切です。


送信の発火源(requestSubmit / ネイティブ / 手動)を正しく選ぶ

ユーザー操作と同等の送信を起こす

<script>
  // 検証を通してから、submit(イベントも)を正規に発火
  if (f.reportValidity()) f.requestSubmit();
</script>
HTML

ここが重要です:ユーザー操作に近い形で送信したいなら requestSubmit。一方 f.submit() は検証やイベントをスキップするので、緊急時の内部送信以外は避けるのが安全です。


まとめ

フォーム送信イベントは「送信直前に介入できる唯一のタイミング」です。基本は submit を監視し、e.preventDefault() で送信を止めて検証や AJAX 送信へ置き換える。HTML の組み込み検証は checkValidity/reportValidity と requestSubmit を組み合わせると自然な体験になります。送信データは FormData(または JSON)で扱い、エラー時は最初の不正要素へフォーカス、進行中はボタン無効化で二重送信を防止。複数ボタンの区別は e.submitter で取得して分岐。これらを押さえれば、初心者でも“壊れない・親切で近代的”なフォーム送信処理が書けます。

タイトルとURLをコピーしました