CommentOut

JavascriptでFormをSubmitする前に入力チェック(バリデーション)を実施する方法 JavascriptでFormをSubmitする前に入力チェック(バリデーション)を実施する方法

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されるという流れになります。

宣伝
WordPressサイトのテンプレート編集やトラブル対応、バグ修正、簡単なJavascriptの作成(カルーセルやバリデーション等)など、小規模なスポット対応を受け付けております。
もしお困りごとがありましたら、お問い合わせフォームよりご相談ください。

この記事を書いた人

uilou

uilou

プログラマー

基本的に、自分自身の備忘録のつもりでブログを書いています。 自分と同じ所で詰まった人の助けになれば良いかなと思います。 システムのリファクタリングを得意としており、バックエンド、フロントエンド、アプリケーション、SQLなど幅広い知識と経験があります。 広いだけでなく、知識をもっと深堀りしていきたいですね。