Rails開発のJavaScriptでのクロージャの使いどころ
今までサーバからブラウザサイドのJavaScriptに値を渡すときに、いちいちHTML要素に余分な属性を付加してそこに値を格納し、JavaScript側でそれを取り出すということをしてきた。例えばこんな感じ。
<div id="1" class="content" title="foo" owner="John" active="true">...</div> <div id="2" class="content" title="bar" owner="Pat" active="false">...</div> <div id="3" class="content" title="buzz" owner="Chris" active="true">...</div>
これらdiv要素の属性、title, owner, active が値を渡すために付加した属性だ。しかしページのあちこちに値を関連付けた要素が増えてくると、ページ中に値をそれらが分散して、どの要素にどの値が関連付けれれているかを知っている必要が出てくる。そもそも、いちいちjQueryなどを使って値を取り出すのも面倒だ。
具体例として、例えば、jQueryUIのダイアログを使って、これらdiv要素をクリックしたときに、ダイアログを表示して、これらの要素を更新したいなんて場合を考えてみよう。だいたい以下のような手順になるだろう。
- JavaScriptでこれらの値を属性から取り出す。
- ダイアログに値を渡してUI(title, owner, active)を初期化する。
- OKボタンを押したときの処理で、これら属性を更新する。
コードにするとこんな感じか。
var content = { initialize: function(id){ // 1. ダイアログに渡すための値を要素から取り出す。 var init_content = function(e){ $("#dialog").dialog({ // 各種処理 // 2. UIの初期化 // 3. OKボタンを押したときの要素の更新処理など }); }; $(id).bind("mouseup", init_content); } };
そして、サーバ側では、各div.content要素を生成する度にcontent.initializeを呼ぶ。
page << "content.initialize(#{content.id})"
しかし、この1と3の手順が結構面倒なのである。何とか成らないかと考えていたところ良い方法を思いついた。
以下のようにする。
var content = { initialize: function(id, title, owner, active){ var init_content = function(e){ $("#dialog").dialog({ // 各種処理 // UIの初期化 }); }; $(id).bind("mouseup", init_content); } };
サーバ側:
page << "content.initialize(#{content.id}, #{content.title}, #{content.owner}, #{content.active})"
content.initialize の引数に title, owner, active を渡すのだ。そうすることで、UIを初期化する際にこれらの値が使えるようになる。
ただし、これだけでは上手くいかない。
content.initialize が呼ばれるのは、要素の初期化時のみ。title, owner, active は、要素を初期化した時点の値なので、ダイアログを表示して値を更新し、もう一度ダイアログを表示したときに前の値が表示されてしまう。
値を何処かに保存しておかなければならないのだ。
そうすると、やっぱり要素の属性として値を保存しておき、必要になったときに取り出すという操作が必要になるのか?
と思ったのだが、よくよくコードを見てみると、content.initialize の引数、id, title, owner, active は、関数 init_content() のクロージャ変数になっているのだ。
だから、OKボタンを押したときの処理で、これらの変数に値を書き戻してやると、次回ダイアログを表示した際に新しい値でUIが初期化されるようになる。
var content = { initialize: function(id, title, owner, active){ var init_content = function(e){ $("#dialog").dialog({ // 各種処理 // UIの初期化 // OKボタンを押したときの処理 title = new_title owner = new_owner active = new_active }); }; $(id).bind("mouseup", init_content); } };
これで、要素の属性に値を取り出したり格納したりする作業から開放される。サーバ側でも、要素を生成するときに余分な属性を付加しなくて良くなる。
大分コードがシンプルになるのではないだろうか。
とりあえず、今日思いついた自分なりのベストプラクティスなのだが、もっと良い方法や一般的に知られている簡単な方法などがあったら教えていただきたい。