🐕

【datalist】入力もしたいしプルダウン選択もさせたい & プルダウン選択で他項目の自動入力

2023/05/24に公開

入力もしたいし、プルダウン選択もさせたい。
って要望があって調べたらdatalist使うのがベストかな、
という結論になったので使い方をメモ。
あと、datalistを選択して他項目に自動で入力させる方法もついでにメモ。

目次
  • やりたかったこと
    1. inputタグみたいに入力させたい、かつ、プルダウンで選択させたい
    • datalistとは
    • カスタムデータ属性とは
    • datalistの使い方(サンプルコード)
    1. プルダウン選択で、他の項目に自動入力させたい
    • プルダウン選択で他項目の自動入力(サンプルコード)
  • まとめ

やりたかったこと

  1. inputタグみたいに入力させたい、かつ、プルダウンで選択させたい
  2. プルダウン選択で、他の項目に自動入力させたい

2は、changeイベントで発火させれば簡単にできたんですが、
1やろうとしてちょっと悩みました。

手っ取り早く知りたい人用に、CodePen載せときます。

1. inputタグみたいに入力させたい、かつ、プルダウンで選択させたい

datalistとは

datalistで実現させるので軽く説明。

datalist要素は、HTML5から新たに追加された要素です。
フォームの入力欄などで入力候補となるデータリストを定義します。

あらかじめサジェストを登録しておくようなイメージです。

カスタムデータ属性とは

value値の設定とJavaScriptでの値の取得に使用するので軽く説明。
カスタムデータ属性(data-*)は、HTML5から新たに追加された要素です。

「data-」の後に1文字以上の文字列(任意)を設定することで、
各HTMLの要素に対し独自の値を設定することができます。

datalistの使い方(サンプルコード)

datalistは、inputタグの下にdatalistタグを配置して使用します。
inputのlistと、datalistのidを同じにすることで紐付けます。

index.html
    <div>
      <label for="fruit">お好きな果物を選んでください:</label>
        <input id="fruit-input1" value="" list="fruit-select1" name="fruit" />
        <datalist id="fruit-select1" class="fruit-select">
          <option value=""></option>
          <option value="りんご" data-id="data1-id1"></option>
          <option value="バナナ" data-id="data1-id2"></option>
          <option value="オレンジ" data-id="data1-id3"></option>
          <option value="ぶどう" data-id="data1-id4"></option>
          <option value="スイカ" data-id="data1-id5"></option>
        </datalist>
        <input
          id="fruit-input-hidden1" type="hidden" name="fruit-Hidden" value="" />
        <label for="price">価格:</label>
        <input id="price1" value="" name="price" />
    </div>

この場合は、「fruit-select1」で紐づけてます。

見た目的には、datalistに設定されたoption項目がサジェスト的な感じで出ます。
ここでは、data-id(カスタムデータ属性)作ってますが、datalist使いたいだけなら不要です。


datalistは、value値が表示される値になるので
selectタグのように裏で持たせたいvalue値は自前でセットしないといけないです。
今回は、changeイベントでhidden項目にセットすることで
selectタグのような使い方ができるようにしてます。

script.js
/****************************************************************
 * @summary change event
****************************************************************/
$(function() {
    $(document).on('change', 'input[name^="fruit"]', function() {
        
        // 一番近いdivタグを取得
        let targetDiv = $(this).closest("div");
        
        let id = null;
        // datalistのdata-id属性の値の取得 ★手入力だとundifined
        id = targetDiv.find(".fruit-select option[value='" + $(this).val() + "']").data('id');
        // hidden項目にセット
        targetHidden = targetDiv.find('input[name^="fruit-Hidden"]');
        targetHidden.val(id);
        
        // 価格表示
        targetVal = targetHidden.val();
        setFruit(targetDiv, targetVal);
    });
});

何個も同じような要素が並んでいた場合を考慮して、
closestで一番近いdivタグを指定して、そこから要素を特定するようにしてます。

optionタグに、data-*(カスタムデータ属性)を使って
value値にセットしたい一意の値を設定しておき、
その値をhidden項目にセットしてます。

2. プルダウン選択で、他の項目に自動入力させたい

プルダウン選択で他項目の自動入力(サンプルコード)

datalistに設定された項目が選択されたときは、
changeイベントで他の項目に自動入力させます。



index.html
    <div>
      <label for="fruit">お好きな果物を選んでください:</label>
        <input id="fruit-input1" value="" list="fruit-select1" name="fruit" />
        <datalist id="fruit-select1" class="fruit-select">
          <option value=""></option>
          <option value="りんご" data-id="data1-id1"></option>
          <option value="バナナ" data-id="data1-id2"></option>
          <option value="オレンジ" data-id="data1-id3"></option>
          <option value="ぶどう" data-id="data1-id4"></option>
          <option value="スイカ" data-id="data1-id5"></option>
        </datalist>
        <input
          id="fruit-input-hidden1" type="hidden" name="fruit-Hidden" value="" />
        <label for="price">価格:</label>
        <input id="price1" value="" name="price" />
    </div>
script.js
/****************************************************************
 * @summary change event
****************************************************************/
$(function() {
    $(document).on('change', 'input[name^="fruit"]', function() {
        
        // 一番近いdivタグを取得
        let targetDiv = $(this).closest("div");
        
        let id = null;
        // datalistのdata-id属性の値の取得 ★手入力だとundifined
        id = targetDiv.find(".fruit-select option[value='" + $(this).val() + "']").data('id');
        // hidden項目にセット
        targetHidden = targetDiv.find('input[name^="fruit-Hidden"]');
        targetHidden.val(id);
        
        // 価格表示 ★ここで自動入力させている
        targetVal = targetHidden.val();
        setFruit(targetDiv, targetVal);
    });
});

/****************************************************************
 * @summary 価格表示
****************************************************************/
function setFruit(targetDiv, targetVal) {
    
    let price = 0;
    // data1-id1の[data1-]を削除する
    targetVal = targetVal.slice(6);
    switch (targetVal) {
        case 'id1':
            price = 100;
            break;
        case 'id2':
            price = 200;
            break; 
        case 'id3':
            price = 300;
            break;
        case 'id4':
            price = 400;
            break;
        case 'id5':
            price = 500;
            break; 
    }

    // 価格設定されていない場合は何も表示しない
    let priceVal = price != 0 ? price + '円' : '';
    // 価格を表示する
    targetDiv.find('input[name^="price"]').val(priceVal);
}

data-idに指定した値を取得して、その値によって書き込む値を判定して、
書き込みさせたい要素にセットしてます。

まとめ

本当は入力もさせるようなデータの持ち方って良くないと思うけど、
要望だから、、、仕方なく、、、。
でもdatalistの存在知らなかったので、良いじゃん〜って思いました。
入力チェックとか楽になったのかはまだ不明だけど、見た目はスッキリしました。

工夫すれば他にもいろいろ活用できそうな気がします。

サンプルコード:
https://github.com/serina-yam/zenn-demo-code/tree/main/how-to-use-datalist

Discussion