【jQuery】セレクトボックスの中身をモーダルウィンドウで表示させて選択させる【Remodalプラグイン使用】

11,940
SELECTBOX MODAL WINDOW

こんにちは。

ここ数回はプロレスの記事しか書いておらず、一体何のブログなんだ?と思われそうなので今回は真面目にコーディングの話でもしようかと思います!

さて、以前とある案件でこのような要望がありました。

「セレクトボックスをモーダルウィンドウでポップアップさせて選択させたい。」

特にスマホだとiPhoneなのかAndroidなのかによってUIがかなり変わってしまうので、見せ方を統一させたいとのことでした。

それではこの要望を叶えるべく、「なるべく楽して」実現させる方法をご紹介しましょう。

実装サンプル

まず最初に実際にサンプルをご覧ください。

サンプル

せっかくなので2017年の新日本プロレス G1クライマックス出場選手を例にセレクトボックスを用意してみました。
複数のセレクトボックスを用意したかったので、AブロックとBブロックでの選手で分けています。

解説

ポイント

今回、セレクトボックスの中身をDOM操作でモーダルウィンドウで表示するための要素として複製します。
セレクトボックスがあった場所にはモーダルウィンドウを開くためのボタンを置いて、セレクトボックス自体は非表示にします。

その上でモーダルウィンドウ上で選択(クリック)した際に元のセレクトボックスにクリックされた項目を選択中にするよう処理を行います。

使用するjQueryプラグイン

モーダルウィンドウを簡単に実装できる「Remodal」を使用します。
こちらからダウンロードして利用できます。

Remodalダウンロード

head内で読み込みます。ディレクトリ名は適時変更してください。

<link rel="stylesheet" href="css/style.css" media="all" rel='stylesheet' type='text/css'>
<link rel="stylesheet" href="js/remodal/remodal.css" media="screen" rel='stylesheet' type='text/css'>
<link rel="stylesheet" href="js/remodal/remodal-default-theme.css" media="screen" rel='stylesheet' type='text/css'>
<script src="https://html.jquery.com/jquery-3.2.1.min.js"></script>
<script src="js/script.js"></script>
<script src="js/remodal/remodal.min.js"></script>

Remodalはデフォルトのまま読み込むだけで大丈夫です。ただし、jsファイルを下記の順番で読み込みさせてください。

<script src="https://html.jquery.com/jquery-3.2.1.min.js"></script>
<script src="js/script.js"></script>
<script src="js/remodal/remodal.min.js"></script>

後述するjQueryによるDOM操作でremodal用の要素を用意するため、script.jsより前にremodalがあると動きません。

HTML

body内が下記になります。

<div class="wrapper">
 <div class="container">
  <h1>SelectBox Remodal Sample</h1>
  <h2>Aブロック</h2>
    <div class="dropdown">
     <select name="a-block">
      <option value="">選択してください</option>
      <option value="a1">“100年に一人の逸材” 棚橋弘至</option>
      <option value="a2">“暴走キングコング” 真壁刀義</option>
      <option value="a3">“混沌の荒武者” 後藤洋央紀</option>
      <option value="a4">“STONE PITBULL” 石井智宏</option>
      <option value="a5">“HEAD HUNTER” YOSHI-HASHI</option>
      <option value="a6">“ジ・アンダーボス” バッドラック・ファレ</option>
      <option value="a7">“制御不能なカリスマ” 内藤哲也</option>
      <option value="a8">“ブルージャスティス” 永田裕志</option>
      <option value="a9">“英国の若き匠” ザック・セイバーJr.</option>
      <option value="a10">“ゴールデン★スター” 飯伏幸太</option>
     </select>
    </div>
   <h2>Bブロック</h2>
   <div class="dropdown">
    <select name="b-block">
      <option value="">選択してください</option>
      <option value="b1">“ビッグ・マイク” マイケル・エルガン</option>
      <option value="b2">“レインメーカー” オカダ・カズチカ</option>
      <option value="b3">“敏腕プロデューサー” 矢野通</option>
      <option value="b4">“THE CLEANER” ケニー・オメガ </option>
      <option value="b5">“バッドボーイ” タマ・トンガ</option>
      <option value="b6">“Cold Skull” SANADA</option>
      <option value="b7">“キング・オブ・ダークネス” EVIL</option>
      <option value="b8">“剛腕” 小島聡</option>
      <option value="b9">“Heart and Honor” ジュース・ロビンソン</option>
      <option value="b10">“世界一性格の悪い男” 鈴木みのる</option>
    </select>
   </div>
  </div>
</div>

セレクトボックスをdivで囲んでいますが、cssで装飾するためで必須ではありません。

CSS

cssは自由です。ただし、今回セレクトボックスの位置にモーダルウィンドウを開くリンクボタンを配置しますので、このリンクボタンをなるべくセレクトボックスとわかるような装飾にした方が良いでしょう。

Javascript

ここが今回の目的を達成するために大事な部分です。

 $(function () {
  // セレクトボックス毎に処理
  $('select').each(function(i){

    // data-selectを追加
    $(this).attr('id', 'select'+i);

    // セレクトボックスの内容をモーダルウィンドウにコピー
    var clone = $(this).clone().appendTo($(this).parent());
    var remodal_clone = $(clone).wrap('<div data-remodal-id="remodal-select'+i+'" class="remodal remodal-select"></div>').after('<button data-remodal-action="close" class="remodal-close bottom-close">閉じる</button>');

    $(remodal_clone).children('option').each(function(){
      var tag_value = $(this).attr("value");
      if ( tag_value == "") {
        $(this).replaceWith('');
      } else {
        var tag_value_plus = 'data-value="'+tag_value+'"';
        $(this).replaceWith('<li '+tag_value_plus+'>'+$(this).html()+'</li>');
      }
    });
    $(remodal_clone).each(function(){
      $(this).replaceWith('<ul>'+$(this).html()+'</ul>');
    });

    // 元のセレクトボックスは非表示
    $(this).css('display','none');

    // 選択中のoption情報取得
    var selected = $(this).find(':selected');
    var selected_val = $(selected).val();
    var selected_text = $(selected).text();
    $('a[href = "#remodal-select'+i+'"]').text(selected_text);

    // モーダルウィンドウを開くリンク生成
    $(this).after('<a href="#remodal-select'+i+'" class="remodal-select-open">'+selected_text+'</a>');

  });

  // モーダルウィンドウの中をクリックした時の動作
  $('.remodal-select').each(function(i){
    var select_id = $(this).data('select');

    $(this).find('li').on('click', function() {

      var text = $(this).text();
      var value = $(this).data('value');

      $('#select'+i).val([value]);

      $('a[href = "#remodal-select'+i+'"]').text(text);

      // class付与
      $(this).siblings().removeClass("selected");
      $(this).addClass("selected");
      $(function() {
        $('[data-remodal-id=remodal-select'+i+']').remodal().close();
      }); 
    });

  });
});

まず始めにセレクトボックスの中身を取り出して、remodal用の要素に複製します。
また複数のセレクトボックスがある場合を想定して、「data-remodal-id=」には個別の番号が付いたidが入るようにします。

次に元のセレクトボックスを非表示にして代わりにモーダルウィンドウを開くリンクボタンを設置します。
この際、選択がリンクボタンのテキストに反映されるようにします。

 $(function () {
  // セレクトボックス毎に処理
  $('select').each(function(i){

    // data-selectを追加
    $(this).attr('id', 'select'+i);

    // セレクトボックスの内容をモーダルウィンドウにコピー
    var clone = $(this).clone().appendTo($(this).parent());
    var remodal_clone = $(clone).wrap('<div data-remodal-id="remodal-select'+i+'" class="remodal remodal-select"></div>').after('<button data-remodal-action="close" class="remodal-close bottom-close">閉じる</button>');
    
    // optionをliに置き換えて複製
    // optionのvalueが空の場合は複製しない
    $(remodal_clone).children('option').each(function(){
      var tag_value = $(this).attr("value");
      if ( tag_value == "") {
        $(this).replaceWith('');
      } else {
        var tag_value_plus = 'data-value="'+tag_value+'"';
        $(this).replaceWith('<li '+tag_value_plus+'>'+$(this).html()+'</li>');
      }
    });
    $(remodal_clone).each(function(){
      $(this).replaceWith('<ul>'+$(this).html()+'</ul>');
    });

    // 元のセレクトボックスは非表示
    $(this).css('display','none');

    // 選択中のoption情報取得
    var selected = $(this).find(':selected');
    var selected_val = $(selected).val();
    var selected_text = $(selected).text();
    $('a[href = "#remodal-select'+i+'"]').text(selected_text);

    // モーダルウィンドウを開くリンク生成
    $(this).after('<a href="#remodal-select'+i+'" class="remodal-select-open">'+selected_text+'</a>');
  });

あとはモーダルウィンドウで項目をクリックした際に非表示となっているセレクトボックスの「selected」を変更するのと、モーダルウィンドウを開くリンクボタンのテキストを変更する処理を行います。

// モーダルウィンドウの中をクリックした時の動作
  $('.remodal-select').each(function(i){
    var select_id = $(this).data('select');

    $(this).find('li').on('click', function() {

      var text = $(this).text();
      var value = $(this).data('value');

      $('#select'+i).val([value]);

      $('a[href = "#remodal-select'+i+'"]').text(text);

      // class付与
      $(this).siblings().removeClass("selected");
      $(this).addClass("selected");
      $(function() {
        $('[data-remodal-id=remodal-select'+i+']').remodal().close();
      }); 
    });
  });

これを踏まえて再度サンプルを確認してみてください。

サンプル

まとめ

このように既存のプラグインとDOM操作(jQueryで十分だと思います)を組み合わせることで「痒いところに手が届く」的な機能を実装することができます。

まぁ、あまり使用することないかもしれないですけど、お役に立てれば幸いです。

ではでは。