セレクトボックスの選択肢を連動させる

いつぞや掲示板の返答で記述したファイルがデスクトップにあってじゃまなので、捨てる前に載せておきます。
セレクトボックス*1の選択肢を連動して動的に操作したいという要望は頻繁に見かけます。


Select.js(Shift_JIS)


/**
 * 選択肢クラス
 * @param parentValue 親の値(null:いつでも表示)
 * @param text 表示テキスト
 * @param value 値
 * @param style CSS(省略可)
 */
function SelectOption(parentValue, text, value, style) {
  
  this.parentValue = parentValue;
  
  this.setOption = function() {
    this.text = text;
    this.value = value;
    if(style) {
      this.style.cssText = style;
    }
  };
  
  return this;
}

/**
 * セレクトボックスクラス
 * @param id セレクトボックスID
 */
function SelectBox(id) {
  
  /**
   * IDに対応オブジェクトを取得
   * @return オブジェクトorNULL
   */
  function getObject() {
    var obj = document.getElementById(id);
    if(!obj.options && ( (typeof obj.length) == "number") ) {
      if(obj.length > 0) {
        obj = obj[0];
      } else {
        obj = null;
      }
    }
    return obj;
  }
  
  // オプションのリスト
  var options = [];
  
  /**
   * オプション登録
   * @param condition 表示条件
   */
  this.registOption = function(option) {
    options[options.length] = option;
  };
  
  // 子のオブジェクト
  var child = null;
  
  /**
   * 子のオブジェクトを設定する
   * @param childObj 子のオブジェクト
   */
  this.setChild = function(childObj) {
    child = childObj;
  };
  
  /**
   * オプション反映
   * @param parentValue 親の値(null:全部表示)
   * ※比較に==を使っているのでundefinedもnullと等しく扱われる。
   */
  this.make = function(parentValue) {
    var obj = getObject();
    if(obj) {
      // 選択肢削除
      obj.options.length = 0;
      // 表示すべき選択肢抽出
      var opt = (parentValue != null) ? [] : options;
      if(parentValue != null) {
        for(var i = 0; i < options.length; i++) {
          if( (options[i].parentValue == null) || (options[i].parentValue == parentValue) ) {
            opt[opt.length] = options[i];
          }
        }
      }
      // 選択肢反映
      obj.options.length = opt.length;
      for(var i = 0; i < opt.length; i++) {
        opt[i].setOption.call(obj.options[i]);
      }
      // 子のオブジェクトにも連鎖反映
      if(child) {
        child.make(obj.value);
      }
    }
  };
  
  return this;
}

HTMLファイル(使用例)

<html>
<head>
<title>セレクトボックス親子関係</title>
<script type="text/javascript" src="Select.js" charset="Shift_JIS"></script>
<script type="text/javascript"><!--

var box1 = new SelectBox("sb1");
box1.registOption(new SelectOption(null, "都道府県", "0", "color:gray;"));
box1.registOption(new SelectOption(null, "東京都"  , "1"));
box1.registOption(new SelectOption(null, "神奈川県", "2"));
box1.registOption(new SelectOption(null, "埼玉県"  , "3"));
box1.registOption(new SelectOption(null, "千葉県"  , "4"));

var box2 = new SelectBox("sb2");
box2.registOption(new SelectOption(null, "区市町村", "0", "color:gray;"));
box2.registOption(new SelectOption("1" , "千代田区", "1"));
box2.registOption(new SelectOption("1" , "中央区"  , "2"));
box2.registOption(new SelectOption("2" , "横浜市"  , "3"));
box2.registOption(new SelectOption("2" , "川崎市"  , "4"));
box2.registOption(new SelectOption("3" , "与野市"  , "5"));
box2.registOption(new SelectOption("4" , "千葉市"  , "6"));

var box3 = new SelectBox("sb3");
box3.registOption(new SelectOption(null, "詳細"    , "0", "color:gray;"));
box3.registOption(new SelectOption("1" , "一番町"  , "1"));
box3.registOption(new SelectOption("3" , "みなとみらい", "2"));
box3.registOption(new SelectOption("6" , "マリンスタジアム", "3"));

box1.setChild(box2);
box2.setChild(box3);

window.onload = function() {
  box1.make(null);
};

//--></script>
</head>
<body>
<form>
<select id="sb1" onchange="box2.make(this.value);"></select>
<select id="sb2" onchange="box3.make(this.value);"></select>
<select id="sb3"></select>
</form>
</body>
</html>


言いたいことは、例えばこのように「(ミニ)クラスを作っちゃえ」ということです。
ここで挙げたクラスSelectOptionSelectBoxは汎用性に欠けます。要件に合わせてクラスを作成し、それを使用すべきです。
適切なクラスを作ることができれば、結果的にソースコードが簡潔になり、オブジェクト指向のコードとなり、メンテナンスも楽になります。

*1:開発ではよく「コンボボックス」と呼ばれますが、コンボはテキストの直接入力も可能なコントロールです。正しくは「プルダウンメニュー」であり、ボックスという表現を使うならば「セレクトボックス」あたりが妥当だ・・・と私は思います。