こんにちはjunです。vue.jsを用いてフォームUIを作成していたところmultipule属性を付与したセレクトボックスで選択した値を$emitする方法についてメモ&共有しようと思います。
セレクトボックスは基本的には以下の様に、プルダウン式のメニューから一つの値を選ぶ要素です。
<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
が付与されます。
チェックボックスにしては値が多く、リストの方が見やすいのでセレクトボックスから複数選択ができる様にするためには、multipleという属性を付与するだけで実装できます。
<select name="sample" multiple>
<option value="1">選択肢1</option>
<option value="2">選択肢2</option>
<option value="3">選択肢3</option>
</select>
実際に$event.target.value
をconsole.log()
で出力して見てみると、選択肢1をクリックしてから他の選択肢も含めましたが帰って来た結果は全て「1」でした。
格納する親コンポーネントのdataもこの様に1から変化ありませんでした。
選択された値は全て配列で帰ってくる様に調整をします。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
プロパティがtrue
かfalse
で選択されたかがわかるので、true
の要素のみ取得して新しい配列を手に入れます。その配列に対して
let values = opt.map(ele=>ele.value);
this.$emit('newInput', values);
map()
を用いてvalue
プロパティのみを抽出したものを新しい配列として返し、それを親コンポーネントに渡します。これで選択したものを配列として渡すことが可能になります。
先ほどの様に選択肢1から順に選択して値の変化を見てみましょう。
取得された値が順番順番に配列で取得できてますね。親コンポーネントにもちゃんと入っています。これでmultipule属性を持ったセレクトボックスの値を$emitすることができます。