JavaScript 逆引き集 | フォームのsubmit防止

JavaScript JavaScript
スポンサーリンク

フォームの submit 防止 — e.preventDefault()

フォームは送信するとページがリロードされます。JavaScriptで「リロードせずに自分の処理をしたい」ときは、submit イベントで event.preventDefault() を呼んで既定動作(送信)を止めます。


基本の使い方

<form id="login">
  <input name="email" type="email" required>
  <input name="password" type="password" required>
  <button type="submit">ログイン</button>
</form>
<script>
  const form = document.getElementById("login");

  form.addEventListener("submit", async (e) => {
    e.preventDefault(); // フォームの既定送信(ページリロード)を止める

    // 自前の処理(例:バリデーション→API送信)
    const fd = new FormData(form);
    const payload = Object.fromEntries(fd.entries());
    console.log("送信内容:", payload);
    // fetch("/api/login", { method: "POST", body: JSON.stringify(payload), headers: { "Content-Type": "application/json" } })
  });
</script>
HTML
  • ポイント: submit イベントの最初で e.preventDefault()。これが「送信を止める合図」。
  • FormData: 入力値は new FormData(form) で楽に取り出せます。

よく使うテンプレート集

バリデーションしてから送信(OKのときだけ送る)

form.addEventListener("submit", async (e) => {
  e.preventDefault();

  const fd = new FormData(form);
  const email = fd.get("email")?.trim();
  const password = fd.get("password")?.trim();

  if (!email || !password) {
    showError("メールとパスワードは必須です");
    return; // 不正なら送らない
  }

  try {
    setLoading(true);
    const r = await fetch("/api/login", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ email, password }),
    });
    if (!r.ok) throw new Error(`HTTP ${r.status}`);
    const json = await r.json();
    onLoginSuccess(json);
  } catch (err) {
    showError(err.message);
  } finally {
    setLoading(false);
  }
});
JavaScript

Enter キーでの送信も止めて、任意のボタンだけ反応

form.addEventListener("submit", (e) => {
  e.preventDefault();
});
document.getElementById("doSearch").addEventListener("click", () => {
  // Enter送信ではなく、このボタンのときだけ処理する
  runSearch();
});
JavaScript

複数フォームで共通ハンドラを使い回す

function handleSubmit(e) {
  e.preventDefault();
  const data = Object.fromEntries(new FormData(e.currentTarget).entries());
  console.log("送信:", data);
}
document.querySelectorAll("form.needs-js").forEach(f => {
  f.addEventListener("submit", handleSubmit);
});
JavaScript

実務でのコツ

  • エラーメッセージ表示: 失敗時はユーザー向け文言を画面に出す。コンソールだけに出すと気づかれない。
  • 二重送信の防止: 送信中はボタンを無効化し、完了で戻す。
const submitBtn = form.querySelector('[type="submit"]');
submitBtn.disabled = true;
try { /* ... */ } finally { submitBtn.disabled = false; }
JavaScript
  • アクセシビリティ: type="submit" は残しつつ、JSで止める。JSが効かない環境でも最低限送信できる設計が望ましい。
  • サーバ側でも検証: クライアント検証は補助。最終チェックは必ずサーバで。

preventDefault と周辺の使い分け

  • preventDefault: 既定動作(フォーム送信、リンク遷移など)を止める。
  • stopPropagation: 親要素へのイベント伝播を止める。既定動作は止めない。
  • return false: jQueryでは「両方の意味」を持つ場合があるが、素のDOMでは preventDefaultstopPropagation を明確に使い分ける。

ありがちなハマりポイントと対策

  • フォームタグ外の処理だけに頼る: 送信ボタンのクリックにハンドラを付けても、Enter送信は通ることがある。
    • 対策: 必ず formsubmit イベントで止める。
  • passive:true のイベントで止めようとする:passive イベントでは preventDefault が効かない。
    • 対策: フォームの submit は通常 passive にしない。
  • ajax成功/失敗後の状態更新忘れ: ローディング解除、エラーテキスト、入力の再フォーカスなどを丁寧に。

練習問題(手を動かして覚える)

<form id="search">
  <input name="q" placeholder="検索語">
  <button type="submit">検索</button>
  <p id="msg"></p>
</form>
<script>
  const f = document.getElementById("search");
  const msg = document.getElementById("msg");

  f.addEventListener("submit", async (e) => {
    e.preventDefault();
    const q = new FormData(f).get("q")?.trim();
    if (!q) { msg.textContent = "検索語を入力してください"; return; }

    msg.textContent = "検索中...";
    try {
      // 疑似検索
      await new Promise(res => setTimeout(res, 500));
      msg.textContent = `「${q}」の検索が完了しました`;
    } catch (err) {
      msg.textContent = "失敗しました";
    }
  });
</script>
HTML

直感的な指針

  • フォームで独自処理をしたいなら、submit で event.preventDefault()
  • 入力値は FormData→オブジェクト化、検証→AJAX→結果反映の順で。
  • 二重送信防止とユーザー向け表示を忘れない。
タイトルとURLをコピーしました