2017/08/23

選択候補付きテキストボックスを作ってみた。

DataListが使いにくかったから

自分で候補を表示する機能を作ってみました。
jQueryなし、html5+javascriptのみで実現できます。
それではやってみましょう。

目次

目標

候補が絞込みできる取り回しが良いテキストボックスを作る。

サンプルコード

test13.html

<!DOCTYPE html>
<html>
  <head>
    <meta content="IE=edge"
          http-equiv="X-UA-Compatible" />
    <link href="./test013css.css"
          rel="stylesheet"
          type="text/css" />
    <title>Selecters</title>
    <script type="text/javascript">
      //第一引数選択対象テーブルID
      //第二引数設定先キーワードテキストボックスID
      //第三引数選択対象テーブル行番号
      function selectedvalue(TargetTableId,<---③ 
                             KeywordTextboxId,
                             selectedindex){
        //フィルター処理対象テーブル取得
        var target = document.getElementById(TargetTableId);
        //フィルター処理キーワード取得
        var keyword = document.getElementById(KeywordTextboxId).value;
        document.getElementById(KeywordTextboxId).value =
                        target.rows[selectedindex].cells[0].innerText;
      }

      //第一引数フィルタリング対象テーブルID
      //第二引数フィルタリングキーワードテキストボックスID
      function exefilter(TargetTableId,KeywordTextboxId){
        //フィルター処理対象テーブル取得
        var target = document.getElementById( TargetTableId );
        //フィルター処理キーワード取得
        var keyword = document.getElementById( KeywordTextboxId ).value;

        //検索処理
        for(i=0;i<target.rows.length;i++){
          for(j=0;j<target.rows[i].cells.length;j++){
            //検索文字列を小文字にしての検索結果
            var resultL =
            target.rows[i].cells[j].innerText.toLowerCase().indexOf(keyword);
            //検索文字列を大文字にしての検索結果           
            var resultU =
            target.rows[i].cells[j].innerText.toUpperCase().indexOf(keyword);
           
            //検索結果がtrueの列は表示する。
            if( resultL === 0 || resultU === 0 ){ <----②
              target.rows[i].style.display='table-row';  
            }
            else{
              target.rows[i].style.display='none';
            }
          }
        }
      }
    </script>
  </head>
  <body>
    <div class="container">
      <main>
        <div id="FilteringInputTextArea">
          <input onkeyup="exefilter('SuggestList','SearchWord');"
                 onfocus="exefilter('SuggestList','SearchWord');"
                 type="text" id="SearchWord"/>
          <div id="SuggestlistArea">   <-----①
            <table id="SuggestList">
              <tr><td onmousedown="selectedvalue('SuggestList','SearchWord',0)">
              AAMSI</td></tr>
              <tr><td onmousedown="selectedvalue('SuggestList','SearchWord',1)">
              AAO</td></tr>
              <tr><td onmousedown="selectedvalue('SuggestList','SearchWord',2)">
              AAP</td></tr>
              <tr><td onmousedown="selectedvalue('SuggestList','SearchWord',3)">
              AARC</td></tr>
              <tr><td onmousedown="selectedvalue('SuggestList','SearchWord',4)">
              AARP</td></tr>
              <tr><td onmousedown="selectedvalue('SuggestList','SearchWord',5)">
              AAS</td></tr>
              <tr><td onmousedown="selectedvalue('SuggestList','SearchWord',6)">
              AAVSO</td></tr>
              <tr><td onmousedown="selectedvalue('SuggestList','SearchWord',7)">
              AAX</td></tr>
        ~~省略~~
              <tr><td onmousedown="selectedvalue('SuggestList','SearchWord',91)">
              DFW</td></tr>
              <tr><td onmousedown="selectedvalue('SuggestList','SearchWord',92)">
              DG</td></tr>
              <tr><td onmousedown="selectedvalue('SuggestList','SearchWord',93)">
              DGA</td></tr>
              <tr><td onmousedown="selectedvalue('SuggestList','SearchWord',94)">
              DGP</td></tr>
              <tr><td onmousedown="selectedvalus('SuggestList','SearchWord',95)">
              DGC</td></tr>             
            </table>
          </div>
        </div>
      </main>
    </div>
  </body>
</html>

test13css.css

* {
  margin : 0;
  padding    : 0;
  box-sizing : border-box;
}

#FilteringInputTextArea{
  display: block;
  background-color: #57DDF9;
  width: 200px;
  height: 400px;

  padding: 10px;
  margin: 10px;
}

#SearchWord{
  width: 100px;
}

#SuggestlistArea{
  display: none;
}

#SearchWord:focus+#SuggestlistArea{
  position: absolute;
  display: block;
  overflow-y: scroll;
  width: 100px;
  height: 150px;
  background-color: #FFFFFF;
}
#SuggestList td{
  width: 100px;
}

#SuggestList td:hover{
  background-color: #F2A2B7;
}

実行例-表示例

実行すると以下のように動作する。
大文字小文字関係なく検索でき、選択肢をクリックすればテキストボックスに反映される。
今回は実験的に左にIE、右にChromeで撮影しました。
どちらでも軽快に動いています。
[なんか変換がうまくいかなくてちょっと画像が荒いです。ご容赦を]

ポイント!

  • テキストボックスの選択肢はdivで包んだtable要素で作成し、
    テキストボックスの隣接要素にする。[test13.htmlの①]
    このdivのサイズ指定が、選択肢が一度に見える個数を決める。
  • 検索結果に基づいて行ごとに、~style.displayに対して
    table-rowもしくはnoneを割り当てる。
    [test13.html中の②]
    行ごとに消さないとポッカリそのセルだけ消えてしまうようだ。

  • クリック(テーブルのセルの上でonousedownイベントが検知)されたなら、
    その行番号のセルの内容をテキストボックスに割り当てる。
    [test13.htmlの①のtable要素の中のtd要素すべて]
    この処理はJavascriptで関数化すると処理が楽である。[test13.htmlの③]

終わりに

今回これを作ってみたのは実は深い理由がありました。
わかりやすく言うとHTML5で登場したdatalistが微妙だっていうことでした。
一番微妙だと思ったのは、件数を多くしてもスクロールバーが出てこずに延々と候補が長くなるという事象・・・。
かっこ悪すぎです。
それじゃselectはどうかといえば、絞込みがこちらはこちらでいささか面倒でした。

というわけで今回は
テキストボックス+divで囲んだtable+javascriptで作ってみたわけです。

サクサク動くものができて満足です。

検索のアルゴリズムを変えれば前方一致ではなく含むものすべてなど
さまざま作ることが可能です。

ご参考になれば幸いです。

ご利用は自己責任で!


0 件のコメント:

コメントを投稿

AWSに手を出してフレームワークも使ってみたが・・・。

サイトを作り直しました。 AWS上に構築した Content created by AXY を作り直しました。 具体的にはbottle.pyを使ったpythonで構築したサイトからPHP7を使用したサイトに再構築しています。 特別何か問題点があったというわけで...