SELECTボックスを選択したら次のSELECTボックスを表示し、選択済みの値は次のSELECTに表示しない

2015-10-29

タイトルが長すぎですが、例えば複数のプランを選択させる際に、SELECTボックスをずら~と表示しても良いのですが、同じプランを選択させたくない場合が有ります。

先ずはサンプル

SELECTさせるのは都道府県にし、最大で5つまでとしました。1つ目を選択すると次のSELECTボックスが表示され、前に選択した値を除外します。また、選択済みのSELECTボックスを再選択した場合は、それ以降を初期化します。

全体のコード

$(function() {
  var pref = ['北海道','青森県','岩手県','宮城県','秋田県','山形県','福島県','茨城県','栃木県','群馬県','埼玉県','千葉県','東京都','神奈川県','新潟県','富山県','石川県','福井県','山梨県','長野県','岐阜県','静岡県','愛知県','三重県','滋賀県','京都府','大阪府','兵庫県','奈良県','和歌山県','鳥取県','島根県','岡山県','広島県','山口県','徳島県','香川県','愛媛県','高知県','福岡県','佐賀県','長崎県','熊本県','大分県','宮崎県','鹿児島県','沖縄県'];
  var max  = 5;
  var is_select  = new Array;
/*
 * 先ずは一件目のセレクトに全ての要素を入れる
 */
  set_pref("#sel_1",is_select);
  
/*
 * セレクトした時
 */
  $(document).on('change','.sel',function(){ 
      var val        = $(this).val();
      var num        = $(this).data('num');
      var nx         = (num*1)+1;
          is_select  = new Array //選択済み都道府県配列
        
   //一つ目のセレクトを未選択にした場合は以降初期化
    if( !$("#sel_1").val() ){
      for(var i=2; i<=max; i++){
          var id = "#sel_"+i;
          $(id).hide();
          $(id+' option').remove();
      }
      return;
    }
    
   //自分より大きいselectを初期化して非表示 *選択肢を変更した場合など
    for(var i=1; i<=max; i++){
      var id = "#sel_"+i;
      if(!val) //変更したとき空なら自身以降を初期化
        num = num-1;
      
      if(i > num){
        $(id).hide();
        $(id+' option').remove();
        $(id).hide();
      }
      if( $(id).val() )
        is_select.push( $(id).val() );
    }

   //select数を超えたら処理しない
    if(num <= max){
      var nx_sel = "#sel_"+nx; //次のselectのid
      $(nx_sel).show();
      set_pref(nx_sel,is_select);
    }
  });
  
/*
 * 都道府県配列から指定selectへoptionを設定する
 */
    function set_pref(select_id,obj){
      $(select_id).append($('<option>').html('▽').val('')); //最初に▽を入れる
      
      for(var i=0; i<pref.length; i++){
        var val = pref[i];
        if( obj ){
         //選択済みの都道府県を除外してセレクトに追加
          if( $.inArray( val, obj )  == -1 ){
            $(select_id).append($('<option>').html(val).val(val));
          }
        }
      }
    }
});

SELECTに設定する配列はご覧の通り都道府県です。

SELECTボックスのHTML
<p><select class="sel" id="sel_1" data-num="1"></select></p>
<p><select class="sel" id="sel_2" data-num="2"></select></p>
<p><select class="sel" id="sel_3" data-num="3"></select></p>
<p><select class="sel" id="sel_4" data-num="4"></select></p>
<p><select class="sel" id="sel_5" data-num="5"></select></p>

jQueryで追加していっても良いのですが、POSTで戻った場合など、jQueryを走らせるよりPHPで処理した方が楽なので、必要な分だけ直で書いています。あと、1番目以降はCSSで非表示に。

 

一軒目のSELECTボックスに都道府県を設定する
/*
 * 先ずは一件目のセレクトに全ての要素を入れる
 */
  set_pref("#sel_1",is_select);

そのfunction set_pref

/*
 * 都道府県配列から指定selectへoptionを設定する
 */
    function set_pref(select_id,obj){
      $(select_id).append($('<option>').html('▽').val('')); //最初に▽を入れる
      
      for(var i=0; i<pref.length; i++){
        var val = pref[i];
        if( obj ){
         //選択済みの都道府県を除外してセレクトに追加
          if( $.inArray( val, obj )  == -1 ){
            $(select_id).append($('<option>').html(val).val(val));
          }
        }
      }
    }

説明が前後しますが、選択済みの都道府県はis_selectにpushしてるので、それを除外しています。

 

セレクトボックスを選択した時の処理
   //一つ目のセレクトを未選択にした場合は以降初期化
    if( !$("#sel_1").val() ){
      for(var i=2; i<=max; i++){
          var id = "#sel_"+i;
          $(id).hide();
          $(id+' option').remove();
      }
      return;
    }

何個か選択した後に、最初のセレクトボックスを変更した場合は、それ以降を初期化して非表示にします。

   //自分より大きいselectを初期化して非表示 *選択肢を変更した場合など
    for(var i=1; i<=max; i++){
      var id = "#sel_"+i;
      if(!val) //変更したとき空なら自身以降を初期化
        num = num-1;
      
      if(i > num){
        $(id).hide();
        $(id+' option').remove();
        $(id).hide();
      }
      if( $(id).val() )
        is_select.push( $(id).val() );
    }

これは5コ選択中のとき、3コ目を再選択した場合の処理です。自身以降を初期化します。また、自身を空にした場合と別な都道府県を選択した場合では表示方法が変わります。

   //select数を超えたら処理しない
    if(num <= max){
      var nx_sel = "#sel_"+nx; //次のselectのid
      $(nx_sel).show();
      set_pref(nx_sel,is_select);
    }

最初に max=5としているので、それ以降はセレクトボックスの追加処理は行いません。

 

簡単に言えば、選択済みの都道府県をis_select配列に追加していき、inArrayでマッチしたものを除外して選択肢としてインサートしていくだけです。

私的&クライアント的に利用頻度の高い処理なのですが、その都度書いていたりしたので、纏めておきます。