HTML の <select> 要素は複数の選択肢から1つを選択させるためのパーツです。特にスマホなどでは入力の負担が大きいため、入力内容が長いケースでは選択肢の中から選ぶことができると利用者の負担を軽くすることができて便利です。

ただ必ずしも全てのケースで「選択肢から選ぶ」ことが可能とは限りません。めぼしい選択肢を用意した上で、それでも選択肢以外の答を入力したい/させたい場合、多くのケースでは「その他」という選択肢を用意した上で、「その他」を選んだ場合のみ、詳しい内容を別のテキストフィールドに入力させる、という方法が取られているように感じます。 これはこれで(最低限の目的を達成することができるという意味で)いいのですが、UI/UX の観点では例外的なパーツ処理となり、見た目にもスマートではありません。

HTML を使わないネイティブアプリケーションなどでは「任意文字列も入力可能なセレクトボックス」のようなパーツも用意されていて、これを使うことで選択肢の中から選ぶことも(ダブルクリックするなどして編集状態に切り替えた上で)任意文字列を入力することもできます。これだと見た目もスマートでいいですよね。というわけで、このようなパーツを HTML でも用意できないか挑戦してみました。目標はこのブログエントリのタイトルでもある『ダブルクリックすると <input> になって任意入力可能な <select> 』の実現です。

説明の前に、まずは実際に動くサンプルを使ってみてください。下の <select> から値を選び、"Value" ボタンをクリックすると、選択されている値が alert() で表示されます。<select> 部分をダブルクリックすると編集可能になって任意文字列が入力可能になり、その上で "Value" ボタンをクリックすると、入力されている値が alert() で表示される、というものです:




そんなに特別なことをしているわけではないのですが、以下解説です。まず HTML での該当箇所は以下のようになっています:
<select id="mySelect">
  <option value="12345">12345</option>
  <option value="23456">23456</option>
  <option value="34567">34567</option>
  <option value="45678">45678</option>
  <option value="56789">56789</option>
</select>
<input type="text" id="myInput" style="display:none;" value=""/>

<select>(id = "mySelect")と <input>(id = "myInput")を1つずつ配置しています。ただし <input> には style="display:none;" を指定して非表示にしています。つまりこの時点では <select> のみが表示されています。先にコツを言っておくと、<select> の値は常に <input> に引き継がれるように(この後で)設定しておき、"Value" ボタンクリック時には <select> ではなく <input> の値を取得するようにします。

次に JavaScript の解説です:
$(function(){
  //. select の値が変わった時のハンドリングを定義
  $('#mySelect').change( onSelectChange );
  onSelectChange();

  //. select がダブルクリックされたら select を非表示にした上で、同じ値が入っている input を表示する
  $('#mySelect').dblclick( function( e ){
    $('#mySelect').css( 'display', 'none' );
    $('#myInput').css( 'display', 'block' );
  });
});

//. select の値が変わったら、その値を隠しフィールドに代入しておく
function onSelectChange(){
  var v = $('#mySelect').val();
  $('#myInput').val( v );
}

まず画面ロード時に <select> の値が変わった時の処理を定義しています。ここでは <select> の値が変わるたびに onSelectChange() が実行され、<select> で選択された値が常に <input> の値として反映されるようにしています(またロード直後に1回実行することで <input> を初期化しています)。

また <select> がダブルクリックされた時の処理も記述しています。ダブルクリックされたら <select> を非表示に、<input> を表示状態に切り替えます。<input> には上述の処理によって常に <select> で選択されていた値が入っているので、その値が引き継がれた状態で編集可能なフィールドとして表示されることになります。

加えて、以下のスタイルシートを適用することで <select> と <input> が同じサイズになるように設定し、ダブルクリック時に <select> が自然に <input> に切り替わったように見えるよう調整しています:
#mySelect{
  height: 40px;
  width: 200px;
}
#myInput{
  height: 40px;
  width: 200px;
}

これでダブルクリックすると <input> に切り替わる <select> を作ることができました。 あとは "Value" ボタンですが、これは onClick 属性に以下のような関数を定義して、<input> に設定された値を取り出すようにしています:
<input type="button" class="btn btn-primary" value="Value" onClick="getValue();"/>
//. 現在の値を取り出す
function getValue(){
  //. select ではなく input に入っている値を取り出す
  var v = $('#myInput').val();
  alert( v );
}

実際のサンプルコードは github で公開しているので、こちらも参照ください:
https://github.com/dotnsf/select2input