JavaScript でリッチなUIを作る場合の覚書(その1)

Webアプリケーションでネイティブアプリに近い操作感を実現したいとなると
Ajaxで取得したデータを使ってコンテンツを描画、さらにそれを操作というのはよくありますね。

例えばajaxでjsonを取得して、handlebars.jsなどを使って一覧を作成したんだけど
各行を jQuery.UI で draggable にしたいんだけど動かない、なんてときの覚書です。

 

想定する仕様は以下の通りです。

  • 通信中はローディングを表示させたい
  • 通信が完了したら取得したjsonを使ってテーブルを作成
  • テーブルの作成が終わったらローディングを終了して、行のドラッグを出来るようにしたい

さっそくですが、コードです。

[javascript]
$(function(){
// ローディングの作成
$(‘body’).append(‘<div id="loading"><img id="loading_circle" src="/img/loading.gif"></div>’);
$(‘#loading’).width($(window).width());
$(‘#loading’).height($(window).height());

$("#loading").bind("ajaxSend", function(){
$(this).fadeTo(600, 0.5);

// ajaxComplete されてからでないとjQueryUI::draggable がbind出来ないため
// ここで各種イベントをliveで実行する
}).bind("ajaxComplete", function(){
$(this).fadeOut(600);

// ドラッグ(&ドロップ、は今回省略)
$("#results tbody tr").live(‘mousedown’, function(){
$(this).draggable({
snap: true,
cursor: ‘move’,
appendTo: "body",
helper: "clone"
});
});
});

// データを取得してテーブル作成
$.ajax({
type: ‘POST’,
url: ‘/path/to/’,
cache: false,
success: function(result) {
var ret = jQuery.parseJSON(result);
var values = {data: ret};
var template = Handlebars.compile($("#result-template").html());
$(‘#results > tbody’).html(template(values));
}
});
});
[/javascript]

ポイントとしては以下。

  1. ローディングの作成にはajaxSend、ajaxCompleteイベントをbindしてやる
  2. ajaxComplete イベントが発火したら mousedown イベントを live で検知
  3. draggableはliveで検知したもので使う

ローディングが終了した(DOMが構築された)後のドラッグ操作、つまりイベントを取得したいので
ajaxComplete にbindしてイベントハンドラを作成します。

さらにそのイベントハンドラ内での実装は新たに構築されたDOMに対して
draggable を使えるようにしたいので live でドラッグ出来る対象オブジェクトの mousedown イベントで draggable をスタートさせます。

ajaxComplete がなんで必要かというと、ロード中またはコンテンツ描画だと
draggableさせる対象のオブジェクトが無いとエラーが発生するわけですね。
なのでdraggableさせる対象のオブジェクトにliveでbindするだけではダメ、というお話でした。

hadnlebars.jsで、なんて書きましたが今回は直接関係は無いです。
     単にネタ元のコードで使ってただけという事で。。

実際のアプリケーションとして実装する場合はMVC/MVVMなフレームワークを使った方がもう少しシンプルにまとめられるかもしれないですが
そのあたりの改訂版はまた後日。