仕事の進みがちょいとアレなので、現実逃避もとい気分転換に。

フォームの入力内容を、jQuery.ajax()を使ってサーバーへ送信したいって時のパターンです。

基本的な流れ

  1. フォームのsubmitを拾う
  2. 通常の送信はキャンセル
  3. 送信ボタンを無効化
  4. 送信先URLやフォームの入力値を取得
  5. 送信
  6. 受信後、送信ボタンを戻す

入力値をどう得るか、というのがポイントかと思います。

送信ボタンを無効化するってのはやらなくても良いんだけど、誤操作防止のためにも是非やって頂きたいと思います。あと送信ボタンの制御以外にも応用がききます。

デモ

なんかお問い合わせフォーム的なものを用意しました。

まー実際にお問い合わせフォームをAjaxで送信する場面なんてないような気もするんですが、基本パターンという事で。

チュートリアル

フォームのsubmitを拾う

一番外側の部分です。あ、対象form要素をid="the-form"としました。

    $('#the-form').submit(function(event) {
        // …
    });

通常の送信はキャンセル

Ajaxで送信するので、通常のフォーム送信はキャンセルします。

    $('#the-form').submit(function(event) {
        // HTMLでの送信をキャンセル
        event.preventDefault();

        // …
    });

送信

先に提示したものと順序が異なりますが、まあそういう形式のAPIなんで仕方がない。このあたりのコールバックの仕組みってのが、JavaScriptのわかりづらいところですよねえ。

    $('#the-form').submit(function(event) {
        // HTMLでの送信をキャンセル
        event.preventDefault();

        // 送信
        $.ajax({
            // …
        });
    });

まだ送信先も内容も、はたまた前後の処理も指定していません。これから記述します。

送信先、形式、内容を取得

    $('#the-form').submit(function(event) {
        // HTMLでの送信をキャンセル
        event.preventDefault();

        // 操作対象のフォーム要素を取得
        var $form = $(this);

        // 送信
        $.ajax({
            url: $form.attr('action'),
            type: $form.attr('method'),
            data: $form.serialize(),

            // …
        });
    });

urlはaction、typeはmethodが対応します。

dataには$form.serialize()で得られる値をそのまま利用できます。内容はname=太郎&mail=…のような形式の文字列ですが、問題ありません。自分で値を取得してきて、JSON的なオブジェクトで渡しても良いのですが、チェックボックスやラジオボタンなんかの値を確実に処理するのは手間です。 .serialize()を使っちゃいましょう。

事前に内容を検証 (validate) したい場合は、送信前に各値を取得して確認してください。今回は触れません。各値の取得方法は過去記事などどうぞ。

二重送信を防止

送信ボタンを、送信前に無効化、完了後に戻す事で、思わずダブルクリックしちゃったみたいなのに対応します。

あと時間切れを設定しておきましょう。サーバーに異常があった際にボタンを戻す等出来ます。(戻しても送信できないかもしれませんが。)

    $('#the-form').submit(function(event) {
        // HTMLでの送信をキャンセル
        event.preventDefault();

        // 操作対象のフォーム要素を取得
        var $form = $(this);

        // 送信ボタンを取得
        var $button = $form.find('button');

        // 送信
        $.ajax({
            url: $form.attr('action'),
            type: $form.attr('method'),
            data: $form.serialize(),
            timeout: 10000,  // 単位はミリ秒

            // 送信前
            beforeSend: function(xhr, settings) {
                // ボタンを無効化し、二重送信を防止
                $button.attr('disabled', true);
            },
            // 応答後
            complete: function(xhr, textStatus) {
                // ボタンを有効化し、再送信を許可
                $button.attr('disabled', false);
            },

            // …
        });
    });

成功、失敗時の処理

    $('#the-form').submit(function(event) {
        // HTMLでの送信をキャンセル
        event.preventDefault();

        // 操作対象のフォーム要素を取得
        var $form = $(this);

        // 送信ボタンを取得
        var $button = $form.find('button');

        // 送信
        $.ajax({
            url: $form.attr('action'),
            type: $form.attr('method'),
            data: $form.serialize(),
            timeout: 10000,  // 単位はミリ秒

            // 送信前
            beforeSend: function(xhr, settings) {
                // ボタンを無効化し、二重送信を防止
                $button.attr('disabled', true);
            },
            // 応答後
            complete: function(xhr, textStatus) {
                // ボタンを有効化し、再送信を許可
                $button.attr('disabled', false);
            },

            // 通信成功時の処理
            success: function(result, textStatus, xhr) {
                // 入力値を初期化
                $form[0].reset();
                
                alert('OK');
            },

            // 通信失敗時の処理
            error: function(xhr, textStatus, error) {
                alert('NG...');
            }
        });
    });

これでおしまい。

実際には

ボタンを無効化するよりも非表示にして、ぐるぐる回る画像なんか置いておくと良さそうですね。 .attr('disabled', true)とかの箇所を .addClass('loading')みたいにして、ってのはどうでしょう。

はい、では仕事に戻ります。 λ…