💨

【Vue3】multiple属性の複数選択プルダウンで選択した値をemitする

2023/08/04に公開

はじめに

vuetify公式を参考に、v-selectで複数選択できるプルダウンを作っていたところ、値を親にemitできず少し沼りました。

template

<template>
  <v-container fluid>
    <v-select
      v-model="selectedFruits"
      :items="fruits"
      label="Favorite Fruits"
      multiple
    >
      <template v-slot:prepend-item>
        <v-list-item
          title="Select All"
          @click="toggle"
        >
          <template v-slot:prepend>
            <v-checkbox-btn
              :color="likesSomeFruit ? 'indigo-darken-4' : undefined"
              :indeterminate="likesSomeFruit && !likesAllFruit"
              :model-value="likesSomeFruit"
            ></v-checkbox-btn>
          </template>
        </v-list-item>
      </template>
    </v-select>
  </v-container>
</template>

script

<script>
  export default {
    data: () => ({
      fruits: [
        'Apples',
        'Apricots',
        'Avocado',
        'Bananas',...略
      ],
      selectedFruits: [],
    }),

    computed: {
      likesAllFruit () {
        return this.selectedFruits.length === this.fruits.length
      },
      likesSomeFruit () {
        return this.selectedFruits.length > 0
      },
    },

    methods: {
      toggle () {
        if (this.likesAllFruit) {
          this.selectedFruits = []
        } else {
          this.selectedFruits = this.fruits.slice()
        }
      },
    },
  }
</script>

selectの値を受け取る

基本的にinput系の値を取得するときは、v-modelを使用しますが、今回はv-bind@inputで入力された値を親コンポーネントに伝える方法をとります。

一択選択の場合

<select>@input="$emit('newInput', $event.target.value)"で、
親コンポーネントはnewInputを用いてセレクトボックスの値を受け取ることができます。

<template>
 <select @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',
 //親から初期値valueを受け取るprops
 props:['inputed'],
 data(){
   return{
     selector:[
          {text:'選択肢1',value:'1'},
          {text:'選択肢2',value:'2'},
          {text:'選択肢3',value:'3'}
     ],
   }
 },
 
}
</script>

複数選択の場合

今回はmultiple属性のついたプルダウンの値をemitしたので、
$event.target.valueではなく、$event.target.optionsを使用します。

template

<v-container fluid>
    <v-select
      v-model="selectedFruits"
      :items="fruits"
      label="Favorite Fruits"
      multiple
      @input="returnValue($event)"  // add
    >
      <template v-slot:prepend-item>
        <v-list-item
          title="Select All"
          @click="toggle"
        >
          <template v-slot:prepend>
            <v-checkbox-btn
              :color="likesSomeFruit ? 'indigo-darken-4' : undefined"
              :indeterminate="likesSomeFruit && !likesAllFruit"
              :model-value="likesSomeFruit"
            ></v-checkbox-btn>
          </template>
        </v-list-item>
      </template>
    </v-select>
  </v-container>

script

<script>
  export default {
    props: ['inputed'],
    data() {
       return {
	   fruits: [
		'Apples',
		'Apricots',
		'Avocado',
		'Bananas',...略
	   ],
	   selectedFruits: [],
       }
    },

    computed: {
      likesAllFruit () {
        return this.selectedFruits.length === this.fruits.length
      },
      likesSomeFruit () {
        return this.selectedFruits.length > 0
      },
    },

    methods: {
      toggle () {
        if (this.likesAllFruit) {
          this.selectedFruits = []
        } else {
          this.selectedFruits = this.fruits.slice()
        }
      },
       returnValue($event){
	    let opt = Object.values($event.target.options).filter(ele=>{
			  return ele.selected;
		      })
	    let values = opt.map(ele=>ele.value);
	    this.$emit('newInput', values);
	}
    },
  }
</script>

$event.target.optionsには``<option>タグに関する情報が入っており、selectedvalueも含まれています。 HTMLCollectionの配列なので、Object.valuesでvalueの配列にしてからfilter()```しました。

最後に、selectedtrueの要素のみ取得して新しい配列を作り、その配列に対してmap()をかけ、valueを抽出したもの新しい配列として返します。
それを親コンポーネントに渡すと、選択したものを配列として渡すことが可能になります。

参考

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

Discussion