今までは、Ajax(非同期)でのファイルアップロードは
iframeを使うなど、少しトリッキーな方法を用いる必要があり、
とても面倒でしたが、『XMLHttpRequest Level2』からは『FormData』というものへ
オブジェクト化すればファイルもサーバーへアップロード出来る様になりました。
しかし『Firefox 3.6』辺りでは上手く動作しない等の報告もあり、
使用に躊躇していましたが、最近の『Firefox』の強制アップデートにより、
古い『Firefox』は駆逐されたかと思いますので、
今回の記事にて、フォームを利用したAjax(非同期)でのファイルアップロード方法について
サンプルコード付きで解説します。
更に、サンプルコードは私が普段使用しているものを分かりやすく纏めたものです。
機能としては、単純なAjax(非同期)処理と、送信先や送信方式等は
送信対象のフォームを解析し、自動的にセット。
送信に対する結果通知は、コールバックを指定するという方式を取り、
汎用的に使いまわせる様にユーザ定義関数として再編しています。
主に、フォームの『submit』の代わりにお使い頂けます。
それでは早速解説に入りましょう。
- コピペでOK!ファイルアップロード対応付Ajax通信
- Ajax通信に必要な要素の初期化
- ファイルアップロード対応のAjax通信用データをフォームから自動取得して成型
- Ajax通信を実行し、返却値を受け取ろう!結果と共にコールバック起動
- フォームデータをAjax通信にて送信する方法
コピペでOK!ファイルアップロード対応付Ajax通信
今回のサンプルコードでは、
主にAjax部分や、要素の解析にはjQueryを使用していますので、
お使いになるときはjQueryも読み込んで下さい。
コピペでも使用出来る用に、少し量は大きいですが
ソースをそのまま表示します。
まずはソースをご覧頂き、ソースを元に解説して行きます。
/* フォームをajax送信(ファイルアップロード対応) -------------------------------------------------------------------------------*/ function ajax_submit( form_, callbacks_ ) { // フォームの指定が無ければ即時返却 if( $.trim( form_id_ ).length <= 0 ) return; // コールバックのデフォルト値を設定 var defaults = { 'begin' : function(){}, 'success' : function(){}, 'error' : function(){}, 'complete' : function(){}, }; // デフォルト値とマージ var callbacks = $.extend( defaults, callbacks_ ); // 開始コールバックを起動 callbacks['begin'](); // フォームオブジェクトを取得 var $form_obj = $(form_); // フォームのデータを元にFormDataオブジェクトを作成 var form_data = new FormData( $form_obj[0] ); // フォームのアクションを取得 var action = $form_obj.attr("action"); // フォームのメソッドを取得 var method = $form_obj.attr("method"); // 非同期通信 $.ajax({ url : action, type : method, processData : false, contentType : false, data : form_data, enctype : 'multipart/form-data', dataType : 'Json', success: function( result ){ // 成功コールバックを起動 callbacks['success'](result); }, error: function(XMLHttpRequest, textStatus, errorThrown){ // 失敗コールバックを起動 callbacks['error'](XMLHttpRequest, textStatus, errorThrown); }, complete : function( result ){ // 完了コールバックを起動 callbacks['complete'](result); } }); }
今回はユーザ定義関数として『ajax_submit( form_id_, callbacks_ )』というものを作成致しました。
まずはお決まりの引数の説明からです。
第一引数には、フォーム要素を渡します。
これは、jQuery用のセレクタでも結構ですし、直接オブジェクトを渡しても問題ありません。
第二引数には、コールバック起動先の関数を連想配列にて指定します。
連想配列の添え字とコールバックタイミングは、
『begin』が処理開始時に起動されるコールバック。
『success』が非同期通信に成功した時のコールバック。
『error』が非同期通信に失敗した時のコールバック。
『complete』が非同期通信の処理が完了した時のコールバックです。
これらを何に使うかと言いますと、
例えば『begin』のタイミングでローディングマークやインジケーターを表示させたり、
逆に『complete』のタイミングでローディングマークやインジケーターを消したりといった処理が、
今回作成する『ajax_submit()』を使う側で簡単に設定出来ます。
『success』と『error』に関しては、それぞれの返却値を利用して
好きな処理へと渡す事が出来ます。
非同期通信処理部分は単なる一機能ですので、汎用的に使いまわせる様に
特質した使い方を書く部分は外出し出来る様に考慮しています。
使い道はそれぞれですし、あり程度処理が決まっているのであれば、
それはそれで関数を作成し、その関数を引数として渡す方が楽かも知れません。
私はインジケータの表示・非表示をそれぞれ関数かし、
表示させながら使用したい時に個別にコールバックとして渡す様にしています。
それでは実際の処理の内容を解説していきます
Ajax通信に必要な要素の初期化
前章で表した関数を分断しながら個別に解説して行きます。
まずは、初期化等を行う初動部分をピックアップしてみましょう。
冒頭の下記ソースをご覧下さい。
// フォームの指定が無ければ即時返却 if( $.trim( form_id_ ).length <= 0 ) return; // コールバックのデフォルト値を設定 var defaults = { 'begin' : function(){}, 'success' : function(){}, 'error' : function(){}, 'complete' : function(){}, }; // デフォルト値とマージ var callbacks = $.extend( defaults, callbacks_ ); // 開始コールバックを起動 callbacks['begin']();
まず、引数で渡されたform_id_を
jQueryが持つトリム関数『$.trim()』にて両脇の空白を除去した後に
文字数をチェックして、指定が無ければ即時返却で終了としています。
続いて、コールバック関数のデフォルトを設定しています。
ここでは、各処理にて引数として渡されていないコールバックを
起動しようとした時にエラーとならない様にする為に、
何も処理しない無名関数にて初期化しています。
ですので、毎回全てのコールバックを定義して引数として渡す必要は無く、
必要なコールバック関数のみ渡す事が出来ます。
実際に、引数と比べて値を成型しているのはjQueryが用意する『$.extend()』を使用します。
『$.extend()』の第一引数には、デフォルト値を纏めた連想配列を指定し、
第二引数にはマージする値(この場合は引数として渡されたコールバック関数郡)を指定します。
『$.extend()』では、第一引数で初期化し、第二引数で上書きする処理を行いますので、
第二引数で指定のあるものは上書きされ、指定の無いものはデフォルト値が適用される様になります。
そして、処理の開始を通知するコールバックとして
『begin』を『callbacks['begin']();』の様にして起動しています。
ファイルアップロード対応のAjax通信用データをフォームから自動取得して成型
続いて、送信対象のフォームを解析する部分を見てみましょう。
解析する部分では、フォーム自身が持つアトリビュートを解析し、
ファイルアップロードにも対応出来る用に、フォーム自体を
『FormData』オブジェクトとして作成し、送信対象の要素を一気に纏め上げています。
それでは早速処理を見て行きましょう。
// フォームオブジェクトを取得 var $form_obj = $(form_); // フォームのデータを元にFormDataオブジェクトを作成 var form_data = new FormData( $form_obj[0] ); // フォームのアクションを取得 var action = $form_obj.attr("action"); // フォームのメソッドを取得 var method = $form_obj.attr("method");
まず、何回もjQueryを使用して要素を取りに行くのは非効率なので、
jQueryオブジェクトとして、一回取得したら変数へと格納しています。
次からフォームへのアクセスは、変数を用います。
フォームのjQueryオブジェクトは、引数で渡されてきた値をセレクタとして使用し、
フォームを特定しています。
続いて、『FormData』オブジェクトの作成です。
FormDataのコンストラクタでフォームを指定すれば、
該当のフォームの要素を利用した『FormData』が作成されます。
『FormData』は、『XMLHttpRequest Level2』からファイルアップロードにも対応しているので、
ファイル参照情等も纏めてオブジェクト化する事が出来ます。
具体的には、『XMLHttpRequest Level2』で送信できるフォーマット(キーとバリューの関係)へ
フォームの要素を成型してくれます。
とても便利ですので、是非とも覚えておいて下さい。
そして、Ajax通信の送信先を、フォームの『action』から取得します。
jQueryの『attr()』メソッドは、引数にアトリビュート名を渡す事により、
該当要素のアトリビュートの値を取得する事が出来ます。
同じ要領で、POSTやGETを指定する『method』の要素も取得して、
通信タイプを設定しましょう。
ちなみに、この辺りでログ出力を吐かせる様にすれば、
送信する値を確認出来て便利です。
この後に解説するサーバーからの返却値も簡単に確認する事が出来ますので、
ログ出力は是非とも実装しましょう。
ログ出力についての解説は、
JavaScript開発のデバッグを加速するlog出力!
をご覧下さい。
Ajax通信を実行し、返却値を受け取ろう!結果と共にコールバック起動
いよいよ非同期通信部分の実装に入ります。
非同期通信を行うには、今回はjQueryの『$.ajax()』を使用します。
『$.ajax()』は、とても簡単に非同期通信を行う事が出来ますので、
とても便利です。
『$.ajax()』では、非同期通信に関わる様々なパラメータを指定して使用します。
中にはコールバックを指定する部分もありますし、今回のサンプルでは紹介しきれないので、
興味のある方はjQueryのリファレンスにて指定できるパラメータを確認して下さい。
それでは実際の処理を見て見ましょう。
// 非同期通信 $.ajax({ url : action, type : method, processData : false, contentType : false, data : form_data, enctype : 'multipart/form-data', dataType : 'Json', success: function( result ){ // 成功コールバックを起動 callbacks['success'](result); }, error: function(XMLHttpRequest, textStatus, errorThrown){ // 失敗コールバックを起動 callbacks['error'](XMLHttpRequest, textStatus, errorThrown); }, complete : function( result ){ // 完了コールバックを起動 callbacks['complete'](result); } });
『url』では、Ajax通信先を指定しますが、
こちらは前章で取得したフォームの『action』で指定した値を使用します。
『type』は通信方式です。同じくフォームの『method』で指定した値を使用します。
『data』には、通信形式にファイルも含め成型された『FormData』オブジェクトを指定します。
『enctype』はファイルアップロードにも対応出来る様に『multipart/form-data』としておきましょう。
『dataType』では、Ajax通信によって返却される値のフォーマットを指定します。
今回は、そのままJavaScriptとして扱える『Json』を指定します。
勿論、返却内容はサーバそれぞれでしょうし、HTMLを指定するのも有りだと思います。
続いて、
『$.ajax()』では、基本的な通信結果をコールバックとして指定する事が出来ます。
『success』はAjax通信に成功した時に起動する関数を指定します。
『error』ではAjax通信に失敗した時に起動する関数を指定します。
『complete』ではAjax通信が完了した時に起動する関数を指定します。
いずれも、引数として返却値が渡されてきます。
エラーの場合はエラー内容を表す値が渡されてきます。
今回のサンプルでは、これらのコールバック起動時に、
予め指定しておいたコールバック関数を起動する様に実装しています。
直接プロパティへコールバック関数を渡さない理由は、
やはりログ出力関係です。
何かしらAjaxから返却が有った場合はログに出力すると、
後にとても分かりやすくて便利です。
ログ出力に関しては、
JavaScript開発のデバッグを加速するlog出力!
をご覧下さい。
フォームデータをAjax通信にて送信する方法
それでは、これまで解説してきた『ajax_submit()』の実際の使い方です。
今回は、フォーム要素と合わせて解説出来る用に、HTMLに送信用ボタンを用意し、
送信用ボタンの『onClick』に直接関数の指定を記述しました。
まずは下記サンプルコードをご覧下さい。
フォームの作り方はHTML標準なので、いつも通りに作成して下さい。
ただ、フォーム自体を判別する為にID要素を指定して下さい。
後はAjax送信したい値を『input』要素として作成して行きます。
勿論、ファイルアップロードも可能なので『input type='file'』も使用出来ますし、
『input type='text'』も『input type='hidden'』も使用出来ます。
Ajax等関係無しに、いつも通りに普通のフォームを作成して下さい。
いつもと事なるのが、要素の送信に使用するのが『submit』ではなく、今回作成した『ajax_submit()』だと言う事です。
『ajax_submit()』の第一引数には、今回作成したフォームのID『#makebillform』を指定しています。
第二引数には、インジケーターを表示させる為に、処理開始時に起動される『begin』と、処理完了時に起動される『complete』を実装しています。
それぞれの処理の中では、インジケーターの表示、非表示を行っています。
このインジケータの表示、非表示に使用している『showIndicator()』と『hiddenIndicator()』は
私が独自に作ったユーザー定義関数です。
コチラの中身も、近々公開したいと思いますが、
まずは、上記の様にコールバックによって好きな処理を行う事が出来る点を押さえておいて下さい。
少し長くなりましたが、ファイルアップロード対応のフォーム要素をAjax通信にて
送信する方法を解説して参りました。
また、こちらは私が普段使用しているライブラリの一部ですので、
引き続きより良くする為に改良を続けたいと思います。
もし、追加で欲しい機能等がありましたら、コメント欄にてリクエスト頂ければ作成したいと思います。
例えば、今検討段階にある機能としては、タイムアウト制御を考えています。
こちらも、実際に要件が挙がってから
実装しようかと考えていますが、現段階ではタイムアウトを必要とした案件も無いので、
この状態で一次公開とさせて頂きました。
追加要件や、バグ報告、より良くする為のアドバイス等頂ければ幸いです。
何卒、宜しくお願い致します。