prototype.jsクックブック04 リストの順序をドラッグ&ドロップで変更する
今回はprototype.jsだけではなくscript.aculo.us - web 2.0 javascriptというprototype.jsを使ったリッチなUIを実現するライブラリも使います。ですので、このサンプルを試すときは必要なJavascriptをscript.aculo.usからダウンロードしてください。
さぁ、今回のテーマはドラッグ&ドロップでリストの順序を変更するUIです。まずは、サンプルをご覧ください。
http://ya-lab.main.jp/prototype-js-cookbook/04_sortable_list/demo.html
リストを掴んで上下すると順序が入れ替わります。かつ、Ajaxを利用して、変更した順序をサーバに送り、帰ってきた文字を上部に表示します(実際はこのCGIの中で順序の保存等の処理を行うことになるでしょう)。
では、まずはHTML+JavaScript側のソースコードから見ていきます。
<html><head> <title>prototype.js Cookbook 04: sortable list"</title> <script type="text/javascript" src="prototype.js"></script> <script type="text/javascript" src="scriptaculous.js"></script> <script type="text/javascript"> // リストの順序が変更された時に呼び出される関数。 // ここで変更後の順序を取り出し(Sortable.serialize)それをパラメータに // サーバに通知している。 function save_list() { var params = Sortable.serialize('sortable_list'); new Ajax.Updater('ajax_message','save_list_order.cgi', { parameters:params, asynchronous:true }); } // リストがソート出来るようにする Event.observe(window, 'load', function() { Sortable.create("sortable_list", { dropOnEmpty:true, containment:["sortable_list"], constraint:false, onUpdate:function(){save_list()} }); }, false); </script> </head> <body> <h1>04: Sortable List Demo</h1> <div id="ajax_message">Original Order: 1,2,3,4</div> <ul id="sortable_list"> <li id="id_1">1. Pineapple</li> <li id="id_2">2. Banana</li> <li id="id_3">3. Orange</li> <li id="id_4">4. KIwi</li> </ul> </body> </html>
ポイントは3点。1点目はSortable.createの箇所。これは最初の引数で指定したidのリストをソータブル(順序変更可能)にするということ。ここではulタグのidであるsortable_listを指定している。
2点目はonUpdateイベント。これは順序が変更になった時に呼び出されるイベントなのですが、気づきにくい重大な落とし穴がある。それはこのonUpdateイベントが有効になるためには各liタグのidがユニークなIDを持っており、且つxxx_nn(xxxは任意の文字列でnnはユニークな数字)というフォーマットでなくてはならない。ここではid_連番としている。
最後はSortable.serialize関数。これは現在のリストの順序を表す文字列を返してくれる。文字列の形式はサンプルで言えば、次のようになる。
sortable_list[]=1&sortable_list[]=2&sortable_list[]=3&sortable_list[]=4
番号部分は先ほどonUpdateで説明したidの番号部分になる。つまりこれをサーバ側で取り出せば、変更後の並びが分かる。
というわけで、サーバ側の処理を見てみよう。
#!/usr/bin/perl -w use strict; use CGI; my $cgi = CGI->new(); my @list = $cgi->param("sortable_list[]"); print $cgi->header; print sprintf ("Updated Order: %s", join(',', @list));
ポイントは$cgi->param("sortable_list[]")だろう、これで変更後の順序を示す番号が取得できるので、ここではjoinして返すようにしている。この要領で保存すれば、順序変更完了だ。
というわけで、今回は終了なのだけど、個人的なこのUIに対する意見を書いておく。今回のサンプルのようにリストを直接ドラッグ&ドロップするやり方はあまり良くないと思う。それよりも各行にハンドルを持たせてドラッグ&ドロップ可能であることを明示的に表現した方が圧倒的に分かりやすい。これに関してはhttp://wiki.script.aculo.us/scriptaculous/show/SortableListsDemoで比べてみると分かりやすいと思う。