HTML
jQuery

単一選択のセレクトボックスを連動させたい

概要

単一選択のセレクトボックスが複数個あって連動させる場合、
ajax通信でn個目の選択状況を反映して~といったことはしたくない。

こういうときなんか楽な方法ってないでしょうか。
以下、optgroupというタグとjQueryを使ってサボる方法。

html のoptgroup

存在を忘れていたけどそういえばこんなタグがあった。

話を分かりやすくするために、セレクトボックス2個の親子関係を例にする。
親の選択が子にも影響するって感じ。

<select name="parent">
    <option value="">(指定なし)</option>
    <option value="1">hogehoge.jp</option>
    <option value="2">Yahoo! Japan</option>
    <option value="3">Test</option>
</select>
<select name="child">
    <option value="">(指定なし)</option>
    <optgroup label="hogehoge.jp">
        <option value="1">hogehoge</option>
        <option value="3">fugafuga</option>
    </optgroup>
    <optgroup label="Yahoo! Japan">
        <option value="2">Yahoo! Japan</option>
        <option value="4">ヤフー知恵遅れ</option>
    </optgroup>
    <optgroup label="Test">
    </optgroup>
</select>

jQuery

jQueryで選択状態の反映を実現する。
ソースコードは…まあ参考までということで。

// 親の選択が変更された場合、子の表示を変更しつつ処理する
$("select[name='parent']").change(function() {
    // 子の選択状態を解除
    $("select[name='child'] option:selected").attr("selected", false);
    $("select[name='child']").val([""]);
    // 子を全て非表示で初期化
    $("select[name='child'] > optgroup").each(function() {
        $(this).attr("hidden", "hidden");
    });
    // 親の選択済みをループさせて子を処理する
    $("select[name='parent'] option:selected").each(function() {
        var val = $(this).val();
        var text = $(this).text();
        // ラベルで比較は気持ち悪いね
        if (val != "") {
            // 親の選択状態が(指定なし)以外の場合、子も限定させる
            $("select[name='child'] > optgroup").each(function() {
                if ($(this).attr('label') === text) {
                    // ラベルが親と一緒の場合、hiddenを消すことで見せる
                    $(this).removeAttr("hidden");
                } else {
                    // ラベルが親と違うから、hiddenで消す
                    // 実は上で既にやってるから要らないけど、一応書いておく
                    $(this).attr("hidden", "hidden");
                }
            });
        } else {
            // 親の選択状態が(指定なし)の場合、全部見せる
            $("select[name='child'] > optgroup").each(function() {
                $(this).removeAttr("hidden");
            });
        }
    });
});