0👍
✅
While I still haven’t found an exact solution to my original question, I’ve found a design pattern that I think solves the issue satisfactorily. By using a computed property with a getter and setter, I can use v-model
on the <select>
without needing watchers or any internal component state.
Vue.component('custom-select', {
template: '#component',
props: ['options', 'value'],
computed: {
valueProxy: {
get() {
return this.value;
},
set(newValue) {
this.$emit('input', newValue);
},
},
},
});
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script type="text/x-template" id="component">
<div id="component">
<select v-model="valueProxy">
<option v-for='option in options' :value="option">
<slot v-bind="{ option }"></slot>
</option>
</select>
</div>
</script>
0👍
Let’s say options
prop is an array of object as below
You can change the event emitter of child component to return object instead of string like this:
<style>
[v-cloak] {
display: none;
}
</style>
<!-- // App -->
<div id="app">
<div v-cloak>
Value in parent: {{selectedValue}}
<br><br>
<custom-select :options='selectOptions' v-model='selectedValue'></custom-select>
</div>
</div>
<!-- // JS Code -->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script type="text/x-template" id="component">
<div id="component">
<select @change="$emit('input', options.find(option => option.value == $event.target.value))">
<option v-for='option in options' :value="option.value">
{{ option.text }}
</option>
</select>
</div>
</script>
<script>
// Mount App
new Vue({
el: '#app',
data() {
return {
selectOptions: [
{ text: 'Apple', value: 'apple', price: '10' },
{ text: 'Banana', value: 'banana', price: '20' },
{ text: 'Strawberry', value: 'strawberry', price: '30' },
],
selectedValue: {}
}
},
// Custom component
components: {
'custom-select': Vue.component('custom-select', {
template: '#component',
props: ['options', 'value'],
})
}
})
</script>
Source:stackexchange.com