3つのを連動させる [Perl][Catalyst][Prototype][Ajax]
3つの<select>を使って、次のようなことをしたい。
最初のselectで地方名を選ぶと、2番目の<select>に県名が表示され、2番目の<select>で県名を選ぶと、3番目の<select>に区市町村名が表示される。これを画面遷移なしで行いたい。
地方名→県名の2段連動なら、prototype.jsのobserve_fieldを使う。catalystからprototypeを使うやり方はこちらが参考になりました。
http://blog.mizzy.org/articles/2005/09/10/htmlPrototype
で、具体的にはtemplateに下記のように書き加える。
<head> 〜中略〜 <script type="text/javascript" src="/prototype.js"></script> 〜中略〜 </head> <body> 〜中略〜 <select id="Region" size=20 style="width:150px;" multiple> <option value="1">北海道 <option value="2">東北 <option value="3">関東 : : </select> [% c.prototype.observe_field( 'Region', { update => 'div_pref' url => c.req.base _ 'list/pref', with => "'body='+value", }) %] <div id="div_pref"> <select id="pref" size=20 style="width:150px;" multiple> </select> </div> 〜中略〜 </body>
これで、地方を選ぶと、list/prefアクションが呼ばれるので、下記のようにコントローラで地方名を受け取り、それを元に県名リストを作成して、置き換える<select>を返す。
my @regions = split(/,/, $c->req->param('Region'));
テンプレートはこう。(<option>だけ渡せばいいような気がするけど、<select>丸ごと置き換えないとうまく行かなかったので、こうなってます)
<select id="pref" size=20 style="width:150px;" multiple> [% FOREACH i IN results %] <option value=[% i.pref_id %]>[% i.pref_name %]</option> [% END %] </select>
しかし、地方名→県名→区市町村名の3段連動となると、うまく動かなかった。単純に[% c.prototype.observe_field %]を増やすだけではだめなようだ。いろいろ調べてみたが、いまいちスパッと答えが見つからず。
仕組みとしては、おそらくDOMツリーが構築された後に、<div id="div_pref">の中身をAjaxで書き換えているが、observe_fieldが監視しているのは書き換えられる前のDOMツリーなので、反応しないんジャマイカ。Ajaxの基礎ができてないので、用語とかいろいろ間違ってるかもしれないが。
で、試行錯誤した結果、次のようにすることで目的は達成できた。
2回目のobserve_field(県名の変化の検知)が、1回目のobserve_field(地方名の変化の検知)のときに発動するように、[% c.prototype.observe_field %]が出力するスクリプトをまねして、直にjavascriptを書いた。
<head> 〜中略〜 <script type="text/javascript" src="/prototype.js"></script> 〜中略〜 </head> <body> 〜中略〜 <select id="region" size=20 style="width:150px;" multiple> <option value="1">北海道 <option value="2">東北 <option value="3">関東 : : </select> <script type="text/javascript"> <!-- function Observe_pref(element, value) { new Ajax.Updater( 'div_cities', '[% c.req.base %]list/cities', { parameters: 'pref='+value, asynchronous: 1, onComplete: function(request) { // ここに付け足したら4段目もいけるかな? } } ) } function Observe_region(element, value) { new Ajax.Updater( 'div_pref', '[% c.req.base %]list/pref', { parameters: 'region='+value, asynchronous: 1, onComplete: function(request) { new Form.Element.EventObserver( 'pref', function( element, value ) { Observe_pref(element, value); } ); } } ) } new Form.Element.EventObserver( 'region', function( element, value ) { Observe_region(element, value); } ); //--> <div id="div_pref"> <select id="Pref" size=20 style="width:150px;" multiple> </select> </div> <div id="div_cities"> <select id="City" size=20 style="width:150px;" multiple> </select> </div>〜中略〜 </body>
以下、参考にさせていただいたサイト。
http://plugins.jquery.com/project/DependentSelectbySilVeR
2段連動、のような気がする。試していない。
2009-05-22
県名→区市町村名の2段連動の例。
JavaScript(ajax) prototype.js によるプルダウン(Selectボックス)2段連動 ( ネットサービス ) - Webメディア開発日記 - Yahoo!ブログ
2段連動。
http://news.kapi.jp/log/view/2153
Form.EventObserverのイベントハンドラを設定したり解除したりについて。
http://osdir.com/ml/web.catalyst.general/2006-02/msg00182.html