Riot.jsでAjaxを使った非同期通信について
はじめに
現在あるプロジェクトで、JavaScript界隈では一時期話題になった(*1) Riot.jsで開発をしている。DBとのデータのやり取りを全てAPI化しているため、APIに非同期に通信しているのだが、ちょっとコケたので(*2)備忘録として書き残す。
開発環境など
Riot.js
のバージョンは2.4.1- Ajaxには
jQuery
を使用 ※$.ajax()
のこと
本題のコード
とりあえず.js
ファイル、.tag
ファイルを見てみよう。今回はペン(ボールペンやシャーペンのことね)のメーカー情報を取得するものを例にする。
・hoge.js
/** * 非同期通信のまま返り値を受け取るメソッド * * @param {object} params パラメータオブジェクト * {string} url コントローラの指定 * {string} method POSTかGET * {string} data_type jsonかxml * {object} datas keyと値の組み合わせ * @return void */ function get_list(params) { return $.ajax({ type : params.method, url : params.url, dataType: params.data_type, data : params.query, }); } // APIサーバのURL var ajax_url = "192.168.99.100:81/"; // 開発中なのでローカルで
・pen_list.tag
<pen-list> <!-- layout --> <div> <ul> <li each="{ val, id in maker_list }"> <label>{ val }</label> <input type="checkbox" name="fuga_{ id }" value="ballpoint[]"> </li> </ul> </div> <!-- javascript --> <script> // 初期マウント時にはない変数を定義 opts.maker_list = {}; this.on('mount', function() { // ajax用にパラメータを設定 var params = { url: ajax_url + '/makers', method: 'GET', data_type: 'json', query: { pen_type: 'ballpoint', // 今回はボールペン lang: 'ja' } }; // メーカーのリストを取得 get_list(params) .done(function(result) { opts.maker_list = result; riot.update(); // ページの更新 }) .fail(function(e) { alert('メーカーの取得に失敗しました'); }); }); </script> <pen-list>
pen-list
タグがマウントされた時にAPIサーバにメーカーリストのリクエストをGETで投げ、
戻り値でメーカー名をcheckbox付きでリスト表示する。
しかし、このままだと動かない。非同期通信だと値が戻ってくる前に処理が先に進むため、riot.update()
が意味を成さない。
対策としてどうしようか思いつかなく、突貫でsetInterval
を使用…
以下コード。
// とりあえずintervalで反映 var timer = setInterval(function() { if (opts.maker_list !== '') { riot.update(); clearInterval(timer); } }, 300);
300msずつopts.maker_list
変数に戻り値がセットされている確認し、セットされていたらpen_list
タグのアップデートを実行。
本当はこのページに遷移する前にリクエストを投げデータを取得し、それを持ってmountすれば済む話なのだが、このページに直接アクセスされることもあるので…
2016/06/17 追記
@bj1024さん、@otoan52さんからtwitter上でコメントを、phiaryさんからコメント・コード例をいただき、上記のコードのjs部分を以下のように修正しました。
// 初期マウント時にはない変数を定義 var self = this; self.maker_list = []; // ajax用にパラメータを設定 var params = { url: ajax_url + '/makers', method: 'GET', data_type: 'json', query: { pen_type: 'ballpoint', // 今回はボールペン lang: 'ja' } }; // メーカーリストの取得 get_list(params) .done(function(result) { self.maker_list = result; self.update(); // ページの更新 }) .fail(function(e) { alert('メーカーの取得に失敗しました'); }); });
修正点は、this.on('mount')
を削除、頭にvar self = this;
とし、self.update();
にした。
今までなぜ動かなかったのか、原因の完全な究明はできてないが(*3)、
動くようになった。情報頂いたお三方、本当にありがとうございました!!
終わりに
マウントされた.tag
内でAjax使って非同期通信すると必ずここにぶち当たるので対策しないといけないのだが、いかんせん知識が足りなさすぎる。
どなたかナイスなアイディアをお持ちの方!是非是非情報をお待ちしております!!(切実)
Riot.js
そのもののコードをちゃんと読もう。(必須)