タイトル: formのsubmit前にjavascriptを呼び出す方法
SEOタイトル: フォーム submit 前 JavaScript 呼出完全ガイド
| この記事の要点 |
|
submit 前に JS を呼ぶ 3 つの方法
1. onsubmit 属性で関数呼出
2. addEventListener(推奨)
const form = document.querySelector('form');
form.addEventListener('submit', (e) => {
const email = form.elements['email'].value;
if (!email.includes('@')) {
e.preventDefault(); // ★ デフォルトの送信を中止
alert('メールアドレスが不正です');
return;
}
// 何もしなければそのまま送信される
});
3. ボタン onclick で submit() 呼出
3 方法の比較
| 方法 | キーボード送信(Enter) | イベント上書き | 推奨 |
|---|---|---|---|
| onsubmit 属性 + return false | OK | 1 つだけ | レガシー |
| addEventListener('submit') | OK | 複数可 | ★ 推奨 |
| button onclick + submit() | NG(Enter キーで漏れる) | 複数可 | 非推奨 |
preventDefault / return false の違い
// 旧式: return false (onsubmit 属性内で有効)
function onSubmit(e) {
if (!valid()) return false; // 送信中止 + イベント伝播も止める
}
// モダン: event.preventDefault()
form.addEventListener('submit', (e) => {
if (!valid()) {
e.preventDefault(); // 送信のみ中止
e.stopPropagation(); // バブリングも止めるなら
}
});
// jQuery の場合 return false は両方 = preventDefault + stopPropagation
$('form').submit(function(e) {
if (!valid()) return false;
});
HTML5 標準バリデーション
属性だけで基本的なバリデーションが効きます:
未入力で送信すると、ブラウザが標準のエラー表示を出して送信を防ぎます。JS は不要です。
Constraint Validation API
HTML5 のバリデーション状態を JS から細かく制御:
const form = document.querySelector('form');
const email = form.elements['email'];
form.addEventListener('submit', (e) => {
// 全フィールド有効か
if (!form.checkValidity()) {
e.preventDefault();
form.reportValidity(); // ブラウザ標準のエラー表示
return;
}
});
// 個別フィールドのチェック
console.log(email.validity);
// {
// valid: false,
// valueMissing: true, // required で空
// typeMismatch: false, // type="email" 形式違反
// patternMismatch: false,
// tooLong: false,
// tooShort: false,
// rangeUnderflow: false,
// rangeOverflow: false,
// stepMismatch: false,
// badInput: false,
// customError: false,
// }
// カスタムエラーメッセージ
email.setCustomValidity('このメールは既に使われています');
email.reportValidity();
// クリア
email.setCustomValidity('');
非同期バリデーション(重複チェック等)
const form = document.querySelector('form');
form.addEventListener('submit', async (e) => {
e.preventDefault(); // ★ 一旦止めて非同期チェック
// HTML5 標準チェック
if (!form.checkValidity()) {
form.reportValidity();
return;
}
// サーバ側で重複チェック
const email = form.elements['email'].value;
const res = await fetch('/api/check-email?email=' + encodeURIComponent(email));
const { exists } = await res.json();
if (exists) {
form.elements['email'].setCustomValidity('既に登録済みです');
form.elements['email'].reportValidity();
return;
}
// OK なら手動で送信
form.submit();
});
React のフォーム例
import { useState } from 'react';
function RegisterForm() {
const [email, setEmail] = useState('');
const [error, setError] = useState('');
const onSubmit = async (e) => {
e.preventDefault();
if (!email.includes('@')) {
setError('メール形式が不正');
return;
}
const res = await fetch('/api/register', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({ email }),
});
if (!res.ok) setError('登録失敗');
};
return (
);
}
Vue 3 のフォーム例
スキーマバリデーション (Yup / Zod / Joi)
// Yup
import * as yup from 'yup';
const schema = yup.object({
email: yup.string().email().required(),
age: yup.number().min(0).max(150).required(),
});
try {
await schema.validate(formData);
} catch (err) {
console.error(err.errors);
}
// Zod
import { z } from 'zod';
const Schema = z.object({
email: z.string().email(),
age: z.number().int().min(0).max(150),
});
const result = Schema.safeParse(formData);
if (!result.success) console.error(result.error);
FAQ
Q: form.submit() で onsubmit イベントが発火しない
A: 仕様です。プログラムから form.submit() を呼ぶと submit イベントはスキップされます。バリデーション後の送信は新しく form.requestSubmit() (モダン環境) を使うと submit イベントも発火します。
Q: Enter キーで送信されてしまう
A: 仕様。submit イベントは Enter でも発火するので addEventListener('submit') なら漏れません。input の Enter を完全に止めたいなら keydown で e.key === 'Enter' && e.preventDefault()。
Q: 二重送信を防ぎたい
A: submit ボタンを btn.disabled = true に。あるいは Vue/React で送信中フラグを管理。