セレクトメニューが2つあって、1つ目のセレクトメニューを選択したら、その値によって2つ目のセレクトメニューの選択肢を入れ替えるというものです。
わざわざ何番煎じか分からないネタを遇えて取り上げたのは、巷でよく見かける「配列にデータを入れて出力する」という方法ではなく、Validなソースでこれをやりたかったためです。
選択肢がやたらと多くなりがちなもの、たとえば県から市を選んだりするフォームなどでよく使われていると思います。
とりあえずセレクトメニュー2つだけ連動させてみました。
XHTML
連動させるセレクトメニューにそれぞれIDが必要。
親セレクトメニューのoption要素につけたクラス名と、子セレクトメニューのoptgroup要素のクラス名を同じにします。
optgroup内に入れた要素が選択された時に入れ替わる選択肢になります。
<label for="select">選択肢1</label> <select name="select" id="select"> <option value="果物" class="fruit">果物</option> <option value="肉" class="meat">肉</option> <option value="魚" class="fish">魚</option> </select> <label for="select2">選択肢2</label> <select name="select2" id="select2"> <optgroup class="fruit" label="果物"> <option value="リンゴ" selected="selected">リンゴ</option> <option value="みかん">みかん</option> <option value="ぶどう">ぶどう</option> <option value="桃">桃</option> </optgroup> <optgroup class="meat" label="肉"> <option value="m1">牛肉</option> <option value="m2">豚肉</option> <option value="m3">鶏肉</option> </optgroup> <optgroup class="fish" label="魚"> <option value="maguro">マグロ</option> <option value="sisyamo">ししゃも</option> <option value="iwashi">イワシ</option> <option value="sanma">サンマ</option> </optgroup> </select>
見ての通り普通にソース書くのとそう変わらんので、javscriptオフでもフォームは機能します。
option要素を持たないselectを作る必要もないからバリデートに怒られる心配もない。
optgroupのラベルはどっちでもいい。
Javscript
headとかで事前にmootools ver1.2のコアファイルを読み込んでおかないと動きません。
window.addEvent('domready', function(){ new SelectSelector($("select"),{change:"select2"}); });
new SelectSelector( $(select ID), { change:"select2 ID"});
最初が親になるセレクトメニュー、その次が子になるセレクトメニューのID。両方とも必須。
mootools Class
jsファイルにコピーしたりscriptタグ内に貼り付けたりしてください。
var SelectSelector = new Class({ Implements: [Options,Events], options: { change:null }, initialize: function(element,options) { this.setOptions(options); this.element = element;//select1 this.change = $(this.options.change);//select2 this.groups = this.change.getChildren();//optgroup this.array = new Hash(); this.groups.each(function(item,index){ this.array.set(item.getProperty('class'), item.getChildren().clone()); }.bind(this)); this.start(); }, start:function() { var self = this; this.groups.destroy(); this.change.grab(new Element("option",{text:"選択してください"})); this.element.addEvent("change",function(e){ var key = self.element.getSelected().getProperty('class'); var opt = self.array.get(key[0]).clone(); self.change.getChildren().destroy(); opt.each(function(item, index){ self.change.grab(item); }); }); } });
やってることの大まかな流れ
- 親セレクトメニュー(以下、親)と子セレクトメニュー(以下、子)を取得
- 子のoptgroupを取得し、さらにその子要素であるoption要素の複製を作って
連想配列(hash)に{class:option}の形式で格納。 - 子のoptgroupを削除してから「選択してください」を入れる
- 親が選択されたら、選択されたoption要素のclass名を取得。
連想配列からclass名をキーに持つ値を取得してクローン作成。 - 取得した要素は配列なので、eachで処理して子に追加。
なんでクローン作るの?と思ったらまずclone()消して試してみてください。