フォームの 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);
}
});
JavaScriptEnter キーでの送信も止めて、任意のボタンだけ反応
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では
preventDefaultとstopPropagationを明確に使い分ける。
ありがちなハマりポイントと対策
- フォームタグ外の処理だけに頼る: 送信ボタンのクリックにハンドラを付けても、Enter送信は通ることがある。
- 対策: 必ず
formのsubmitイベントで止める。
- 対策: 必ず
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→結果反映の順で。
- 二重送信防止とユーザー向け表示を忘れない。
