Reputation: 7006
Vue.js has an example demonstrating how to build a functional component wrapping a button:
<template functional>
<button
class="btn btn-primary"
v-bind="data.attrs"
v-on="listeners"
>
<slot/>
</button>
</template>
But how can I build a similar component working with select
which I can then use v-model
on its parent?
I have come up with the following, but when I use v-model
on it like so:
<MyComponent :Label="'Status'" :Data="Statuses" v-model="selectedStatus" />
The value of selectedStatus
becomes:
[object Event]
<template functional>
<select v-bind:value="data.attrs" v-on="listeners">
<option>-</option>
<option v-for="item in props.Data" :key="item" :value="item">{{item}}</option>
</select>
</template>
<script lang="ts">
import { Component, Prop, Vue } from "vue-property-decorator";
@Component
export default class TaskSelector extends Vue {
@Prop({ type: String, required: true })
public Label!: string;
@Prop({ type: Array, required: true })
public Data!: string[];
}
</script>
Upvotes: 2
Views: 2166
Reputation: 138586
For v-model
to work properly, the component must receive a value
prop and emit an input
event whose data is a string value. But the <select>
's native input
event data is an InputEvent
object, converted to a string ([object Event]
), which yields the incorrect result with the bound v-model
.
To fix this, we need to modify the <select>
's input
event data before it reaches the parent. This requires removing <select v-on="listeners">
, which would've allowed the problematic native input
event to propagate to the parent. We then use listeners.input($event.target.selectedOptions[0].value)
to forward the input
event with the selected option's string value.
Steps:
value
prop, and bind the <select>
's :value
to the value
prop<select>
's input
event with the selected option's value. This should replace v-on="listeners"
.Your SFC should look like this:
<template functional>
<select
1️⃣:value="props.value"
2️⃣@input="listeners.input && listeners.input($event.target.selectedOptions[0].value)"
>
<option value="">-</option>
<option v-for="item in props.Data" :key="item" :value="item">{{item}}</option>
</select>
</template>
Upvotes: 5