multiple属性での複数選択セレクトボックスで選択した値をemitする方法。
技術スタック JavascriptVue.js

multiple属性での複数選択セレクトボックスで選択した値をemitする方法。

2020.08.03

こんにちはjunです。vue.jsを用いてフォームUIを作成していたところmultipule属性を付与したセレクトボックスで選択した値を$emitする方法についてメモ&共有しようと思います。

vueを用いてselectの値を受け取る

セレクトボックスは基本的には以下の様に、プルダウン式のメニューから一つの値を選ぶ要素です。

<select name="sample">
 <option value="1">選択肢1</option>
 <option value="2">選択肢2</option>
 <option value="3">選択肢3</option>
</select>

基本的にinput系の値を取得するときはv-modelを使用するのが定石ですが、v-modelでは解決できないコンポーネントの状況もあるでしょう。私もv-modelという糖衣構文ではなくv-bind="~~~", @input="$emit(~~~~)"という形で入力された値を親コンポーネントに返す様にしていました。

一択のセレクトボックスであれば以下の様に記述できます。

<template>
 <select name="postName" @input="$emit('newInput', $event.target.value)">
   <option v-for="val in selectBox"
           :value="val.value" 
           :selected="inputValue === val.value">
           {{val.text}}
   </option>
 </select>
</template>

<script>
export default{
 name:'childSelect',
 props:['inputed'],  //親コンポーネントから初期値のvalueを受け取るためのprops
 data(){
   return{
     selector:[
          {text:'選択肢1',value:'1'},
          {text:'選択肢2',value:'2'},
          {text:'選択肢3',value:'3'}
     ],
   }
 },
 
}
</script>

この様にすることで親コンポーネントではnewInputを用いてこのセレクトボックスからの値を受け取ることができます。

もし編集画面など、セレクトボックスに予め選択済みの設定を行う場合はpropsにvalueの値を入れておけば、一致する選択肢にselectedが付与されます。

Multipuleで複数選択を可能にする

チェックボックスにしては値が多く、リストの方が見やすいのでセレクトボックスから複数選択ができる様にするためには、multipleという属性を付与するだけで実装できます。

<select name="sample" multiple>
 <option value="1">選択肢1</option>
 <option value="2">選択肢2</option>
 <option value="3">選択肢3</option>
</select>

実際に$event.target.valueconsole.log()で出力して見てみると、選択肢1をクリックしてから他の選択肢も含めましたが帰って来た結果は全て「1」でした。

格納する親コンポーネントのdataもこの様に1から変化ありませんでした。

multipleの場合は$event.target.options

選択された値は全て配列で帰ってくる様に調整をします。inputされた時、以下の様に値を取得する様に変更します。

<template>
 <select name="postName" @input="returnValeu($event)" multiple>
   <option v-for="val in selectBox"
           :value="val.value" 
           :selected="inputValue === val.value">
           {{val.text}}
   </option>
 </select>
</template>

<script>
export default{
 name:'childSelect',
 props:['inputed'],  //親コンポーネントから初期値のvalueを受け取るためのprops
 methods:{
  returnValeu($event){
    let opt = Object.values($event.target.options).filter(ele=>{
                  return ele.selected;
              })
    let values = opt.map(ele=>ele.value);
    this.$emit('newInput', values);
  }
 }
 data(){
   return{
     selector:[
          {text:'選択肢1',value:'1'},
          {text:'選択肢2',value:'2'},
          {text:'選択肢3',value:'3'}
     ],
   }
 },
 
}
</script>

処理が少し長めなのでmethodに切り分けました。returnValeu($event)の中身で、イベント(選択)が発生したターゲットの要素を捉えるまでは同じですが、その中にvalueではなくてoptionsというプロパティがあります。

$event.target.optionsは配列ですがHTMLCollectionなのでObject.valuesをもちいて、filter()が使用できる様にしています。

$event.target.optionsには選択肢の<option></option>部分に関する情報が入っており、選択されたか(selected)とその値(value)というプロパティがあります。

let opt = Object.values($event.target.options).filter(ele=>{
  return ele.selected;
})

ここでselectedプロパティがtruefalseで選択されたかがわかるので、trueの要素のみ取得して新しい配列を手に入れます。その配列に対して

let values = opt.map(ele=>ele.value);
this.$emit('newInput', values);

map()を用いてvalueプロパティのみを抽出したものを新しい配列として返し、それを親コンポーネントに渡します。これで選択したものを配列として渡すことが可能になります。

値を出力してみる

先ほどの様に選択肢1から順に選択して値の変化を見てみましょう。

取得された値が順番順番に配列で取得できてますね。親コンポーネントにもちゃんと入っています。これでmultipule属性を持ったセレクトボックスの値を$emitすることができます。

Copyright © 2021 jun. All rights reserved.