[mootools]セレクトメニューを連動させて動的に選択肢を変更する

セレクトメニューが2つあって、1つ目のセレクトメニューを選択したら、その値によって2つ目のセレクトメニューの選択肢を入れ替えるというものです。
わざわざ何番煎じか分からないネタを遇えて取り上げたのは、巷でよく見かける「配列にデータを入れて出力する」という方法ではなく、Validなソースでこれをやりたかったためです。
選択肢がやたらと多くなりがちなもの、たとえば県から市を選んだりするフォームなどでよく使われていると思います。
とりあえずセレクトメニュー2つだけ連動させてみました。

XHTML

連動させるセレクトメニューにそれぞれIDが必要。
親セレクトメニューのoption要素につけたクラス名と、子セレクトメニューのoptgroup要素のクラス名を同じにします。
optgroup内に入れた要素が選択された時に入れ替わる選択肢になります。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<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のコアファイルを読み込んでおかないと動きません。

1
2
3
window.addEvent('domready', function(){
    new SelectSelector($("select"),{change:"select2"});
});

new SelectSelector( $(select ID), { change:"select2 ID"});
最初が親になるセレクトメニュー、その次が子になるセレクトメニューのID。両方とも必須。

mootools Class

jsファイルにコピーしたりscriptタグ内に貼り付けたりしてください。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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);
            });
        });
    }
});

やってることの大まかな流れ

  1. 親セレクトメニュー(以下、親)と子セレクトメニュー(以下、子)を取得
  2. 子のoptgroupを取得し、さらにその子要素であるoption要素の複製を作って
    連想配列(hash)に{class:option}の形式で格納。
  3. 子のoptgroupを削除してから「選択してください」を入れる
  4. 親が選択されたら、選択されたoption要素のclass名を取得。
    連想配列からclass名をキーに持つ値を取得してクローン作成。
  5. 取得した要素は配列なので、eachで処理して子に追加。

なんでクローン作るの?と思ったらまずclone()消して試してみてください。

コメントを残す

This site uses Akismet to reduce spam. Learn how your comment data is processed.