JavascriptでFormをSubmitする前に入力チェック(バリデーション)を実施する方法
以前から、FormをSubmitする時、PHPで入力値をチェックして、ダメだったら何もせずメッセージを表示するのって「無駄な通信だな」「先にJavascriptで入力値をチェックできたら良いのに」って思っていました。
でも、入力チェックの良い設計が思いつかなかったんです。
今回、それなりの形になったので、ご紹介します。
フォームの入力チェック(バリデーション)
今回のサンプルで想定しているformは以下の通り
<form class="v-form" action="" method="POST" enctype="multipart/form-data">
<div>
<label>名前</label>
<input type="text" class="v-text-required" name="Name" placeholder="田中 太郎" />
</div>
<input type="submit" value="送信"/>
</form>
まず、formが送信(submit)された時、必須入力のフォームに値が入力されているかどうかを調べる関数を用意します。
// テキストフィールドの未入力を検証
function textRequired(element) {
if ($(element).val()) {
if (!$(element).hasClass('is-invalid')) {
$(element).addClass('is-valid');
$(element).nextAll('.invalid-feedback').remove();
}
} else {
$(element).removeClass('is-valid');
$(element).addClass('is-invalid');
$(element).parent().append(`<div class="invalid-feedback">未入力です。</div>`);
}
}
$(function() {
// (1)<form class="v-form"> がsubmitされた時に実行
$('.v-form').on('submit', function() {
// (2)form内の <input class="v-text-required" /> を全てチェック
$(this).find('.v-text-required').each(function(index, element) {
// (3)未入力をチェックする
textRequired(element);
});
});
});
(1)formのsubmitをトリガーにして、入力のチェックを行います。
(2)form内のclass=”v-text-required”が付いている要素を順にチェックします。
(3)textRequired関数を呼び出して、入力チェックを行います。
そして、textRequired関数ではelementの値をチェックし、入力がない場合はelementにclass=”is-invalid”(無効)を付けます。
この時、class=”is-valid”(有効)が付いていたら解除します。
そして、入力フォームの下に「未入力です。」と入力要件を表示します。
もし、入力があれば、既にclass=”is-invalid”(無効)が付いていない場合だけ、class=”is-valid”(有効)を付けます。
1つでも無効な条件があれば、サーバーに送信せず入力値の修正を行う必要があるため、有効より無効が優先されます。
ただ、上記サンプルでは問題があって、トリガー自体は発火するのですが、そのままformが送信されてしまいます。
javascriptでformの送信(submit)を止める
formの入力チェックを実施するために、formの送信を一旦止める必要があります。
入力内容に問題があって、formの送信を完全に止める時には「return false;」を使いますが、一時的に止めるにはどうするのが良いでしょうか。
formの送信(submit)を一時的に止めるには、event.preventDefault()を使いましょう
event.preventDefault()はデフォルトの処理を停止させる関数です。
これをsubmit時の関数内で呼ぶと、formがSubmitされなくなります。
// テキストフィールドの未入力を検証
function textRequired(element) {
// さっきと同じ
}
$(function() {
// <form class="v-form"> がsubmitされた時に実行
$('.v-form').on('submit', function(e) {
// デフォルトの処理を停止させる
e.preventDefault();
// form内の <input class="v-text-required" /> を全てチェック
$(this).find('.v-text-required').each(function(index, element) {
textRequired(element);
});
// エラー数をカウント
if ($(this).find('.is-invalid').length) {
console.log(`Error: ${$(this).find('.is-invalid').length}`);
// エラーが1件でもあれば処理を止める
return false;
}
});
});
これでformが送信されなくなります。
そうすると、今度は入力チェック後に問題がなかったとしてもformがSubmitされなくなってしまいました。これ厄介なんですよね。
「Javascript Form Submitさせる」などで検索すると、$(‘form’).submit();などが出てくるんですが、formの送信をトリガーにしている上記サンプルでこの処理を行うと、今度は無限ループが発生します。
submitをトリガーにした関数の中で、submitを呼んでいるのですから、またトリガーが発火して関数が実行され、また関数内でsubmitが呼ばれて・・・の繰り返しになってしまいます。
でも、送信ボタンをトリガーにすると、$(this).find()で同じform内の要素を探せなくなる?探すコードが長くなってしまう?ので、formのsubmitをトリガーにはしておきたいところです。
event.preventDefault()をキャンセルする
さて、そうなったらどうするか・・・
私はそこで頭を悩ませていたんですが、最近良さ気な方法を見つけました。
// テキストフィールドの未入力を検証
function textRequired(element) {
// さっきと同じ
}
// フォームチェックを行う関数
function checkingFields(event) {
// デフォルトの処理を停止させる
e.preventDefault();
// form内の <input class="v-text-required" /> を全てチェック
$(this).find('.v-text-required').each(function(index, element) {
textRequired(element);
});
// エラー数をカウント
if ($(this).find('.is-invalid').length) {
console.log(`Error: ${$(this).find('.is-invalid').length}`);
return false;
}
// エラーが無ければ、submitをトリガーにしてこの関数呼び出しを停止する
$(this).off('submit', checkingFields);
// ↑で関数呼び出しを停止した上で、再度submit => 1度Validationを通っているので、Validation無しで普通に送信される
$(this).submit();
}
$(function() {
// <form class="v-form"> がsubmitされた時に実行
$('.v-form').on('submit', checkingFields);
});
こんな感じで落ち着きました。
$(element).on();と$(element).off();を使い分けます。
今までon()に無名関数を直接代入していましたが、後でoff()できるように、関数名を付けて定義しましょう。
formがsubmitされると、1度 $(‘.v-form’).on(‘submit’, checkingFields); を動かして、checkingFields関数の中を通します。
そして、関数内でエラーが確認できなければ、 $(this).off(‘submit’, checkingFields); を設定し、checkingFields関数が呼ばれないようにした上で、再度 $(this).submit(); でsubmitさせます。
2回目のsubmitでは、checkingFieldsがoffされているため、そのままサーバーへsubmitされるという流れになります。
もしお困りごとがありましたら、お問い合わせフォームよりご相談ください。