(104) SELECTの代替、オプション選択モーダル画面を作る。

投稿者: | 2021年3月6日

1. やりたいこと

入力フォームで、ユーザーに既存の選択肢から一つを選ばせたいときに、SELECTタグ(=COMBOBOX)を使用する。

SELECTは歴史が古く、パソコンの世界で市民権を得ており、多くの人が長年使い慣れている。
その存在を見れば何をさせたいかが容易にわかる、便利なものだ。

でも…
SELECTは、選択肢が多いと一覧性が悪化し、見づらい
と思う。

そこで…
SELECTの代替策として、選択肢を一覧表示するポップアップ画面を作りたい
と思った。

2. やってみる

(1) 方針

1) 入力欄をクリックすると、ポップアップ画面表示される。
2) ポップアップ画面上の選択項目をクリックすると、入力欄に反映され、ポップアップが閉じる。
これだけだ。

(2) 実装したコード

ミニマム実装を記録しておく。
後日この機能を使いたくなった時に、ひな型としてコピペして使えればよいと思った。

このコードを以下に設置した。
https://www.dogrow.net/hp/sample/00104/

この入力欄では、選択肢一覧からユーザーに一つを選択させたい。でも SELECTではない。

入力欄をクリックすると、選択肢一覧画面がポップアップ表示される。

index.html

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="utf-8" />
  <script src="jquery-3.5.1.min.js"></script>
  <script src="script.js"></script>
  <link rel="stylesheet" href="style.css" />
</head>
<body>
  <div id="bg">
    <div class="select">
      <a data-hid="1">山田</a>
      <a data-hid="2">高橋</a>
      <a data-hid="3">佐藤</a>
      <a data-hid="4">田中</a>
      <a data-hid="5">篠塚</a>
    </div>
  </div>

  <form target=''>
    <p>
      <input class="selectId" type="text" name="p1_name" data-hid="p1_id" value="" readonly>
      <input type="hidden" name="p1_id" value="">
    </p>
    <p>
      <input class="selectId" type="text" name="p2_name" data-hid="p2_id" value="" readonly>
      <input type="hidden" name="p2_id" value="">
    </p>
  </form>
</body>
</html>

style.css

/* モーダル画面の背景 */
div#bg{
  position: absolute;        /* 親要素に対して絶対座標で表示 */
  display: none;             /* 初期状態は非表示 */
  top: 0; left: 0;           /* 左上隅から表示 */
  width: 100%; height: 100%; /* 画面いっぱいに表示 */
  background-color: rgba(0, 0, 0, 0.5); /* 背景は黒色透過 */
}
/* モーダル画面(選択肢一覧画面)本体 */
div.select{
  position: absolute;
  top: 1rem; left: 50%;
  transform: translateX(-50%);
  width: 80%;
  background-color: #fff;
  padding: 1rem;
}

/*** 以下、不要な装飾 ***/
html{
  font-size: 20pt;     /* フォント基準サイズを定義 */
}
body{
  margin: 0;
  padding: 1rem;
}
a{
  cursor: pointer;     /* カーソルポインタ */
}
input[type="text"]{
  font-size: 1rem;
  padding: 0.2rem;
}
div.select a{
  display: inline-block;
  padding: 0.3rem;
  background-color: #ffd;
  color: #00f;
}
div.select a:hover{
  background-color: #ff0;
  color: #f80;
}

script.js

$(function(){
  // 選択肢表示画面を表示
  $('input.selectId').click(function(){
    openSelectWindow("#bg", this.name, $(this).attr('data-hid'));
  });
});
// 選択肢表示画面を表示:汎用的に使えるように分離
function openSelectWindow(bgId, obj_name, obj_hid){
  // 本関数が呼ばれたら表示
  $(bgId).css("display","block");
  // 押されたら非表示に
  $(bgId).unbind().click(function(){
    $(this).css("display","none");
  });
  // 選択肢が押されたら inputに値を表示
  $(bgId+' .select a').unbind().click(function(){
    $('input:text[name="'   + obj_name + '"]').val($(this).html());
    $('input:hidden[name="' + obj_hid  + '"]').val($(this).attr('data-hid'));
  });
}

12, 16行目の unbind() でイベントを無効化しなければならない。
これを書かなかった場合、過去にポップアップ画面を開いた数だけイベントが重複発行されてしまう。

この部分は、以下のように書き換えることができる。
$(セレクタ).off(‘click’) と書き換えても clickイベントを unbindできる。

  // 選択肢が押されたら inputに値を表示
  $(bgId+' .select a').click(function(){
    $('input:text[name="'   + obj_name + '"]').val($(this).html());
    $('input:hidden[name="' + obj_hid  + '"]').val($(this).attr('data-hid'));
    $(bgId+' .select a').off('click');
  });

3. やってみる 【改良その1】

(1) 方針

上記の index.html22,23行目26,27行目では、name属性に p{n}_id のように序数を書いていた。
今回はこの部分を p_id[ ] のように配列に書き換え、序数を隠ぺいしたい。

(2) 実装したコード

このコードを以下に設置した。
https://www.dogrow.net/hp/sample/00104/index2.php

index2.html

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="utf-8" />
  <script src="jquery-3.5.1.min.js"></script>
  <script src="script2.js"></script>
  <link rel="stylesheet" href="style.css" />
</head>
<body>
  <div id="bg">
    <div class="select">
      <a data-hid="1">山田</a>
      <a data-hid="2">高橋</a>
      <a data-hid="3">佐藤</a>
      <a data-hid="4">田中</a>
      <a data-hid="5">篠塚</a>
    </div>
  </div>

  <form target="">
    <p>
      <input class="selectId" type="text" name="p_name[]" data-hid="p_id[]" value="" readonly>
      <input type="hidden" name="p_id[]" value="">
    </p>
    <p>
      <input class="selectId" type="text" name="p_name[]" data-hid="p_id[]" value="" readonly>
      <input type="hidden" name="p_id[]" value="">
    </p>
  </form>
</body>
</html>

style.css
変更なし。

script2.js

$(function(){
  // 選択肢表示画面を表示
  $('input.selectId').click(function(){
    // 押された要素の序数を取得
    var i = $('input[name="'+this.name+'"]').index(this);
    // 選択肢表示画面を表示
    openSelectWindow("#bg", this.name, $(this).attr('data-hid'), i);
  });
});
// 選択肢表示画面を表示:汎用的に使えるように分離
function openSelectWindow(bgId, obj_name, obj_hid, i){
  // 本関数が呼ばれたら表示
  $(bgId).css("display","block");
  // 押されたら非表示に
  $(bgId).unbind().click(function(){
    $(this).css("display","none");
  });
  // 選択肢が押されたら inputに値を表示
  $(bgId+' .select a').unbind().click(function(){
    $('input[name="' + obj_name + '"]').eq(i).val($(this).html());
    $('input[name="' + obj_hid  + '"]').eq(i).val($(this).attr('data-hid'));
  });
}

4. 所感

・パソコンの場合、とても見やすい。
・スマホの場合、一覧性よりも大きな文字で表示される方が大事か? ならば SELECTの方がよいかも…
・スマホの場合、古い機種だと表示が重い… 透過をやめたら軽いか?
・スマホページへの適用は、上記の問題点について要検討だなぁ…


コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です


日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)