Reputation: 8078
Is there a way to simplify this code?
The button should also change the localValue of the child.
Vue.component('my-input', {
template: `
<div>
<b>My Input:</b> <br>
localValue: {{ localValue }} <br>
<input v-model="localValue">
</div>
`,
props: ['value'],
data() {
return { localValue: this.value }
},
watch: {
value () {
this.localValue = this.value
},
localValue () {
this.$emit('input', this.localValue)
}
}
})
new Vue({
el: '#app',
data: () => ({
parentValue: 'Inital value'
}),
methods: {
change () {
this.parentValue = 'Changed value'
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.3/vue.min.js"></script>
<div id="app">
<my-input v-model="parentValue"></my-input>
<button @click="change">Change</button><br>
parentValue: {{ parentValue }}
</div>
I have always faced difficulties when I need to do so.
I will be very grateful for the help!
Upvotes: 7
Views: 8614
Reputation: 164730
If you avoid using v-model
inside your custom form component, you really only need
<b>My Input:</b> <br>
localValue: {{ value }} <br>
<input :value="value" @input="$emit('input', $event.target.value)">
No data
, no watch
, that's it.
See https://v2.vuejs.org/v2/guide/components.html#Using-v-model-on-Components
If you really want something representing a value local to your component, the Vue docs favour using computed values over watchers (ref: https://v2.vuejs.org/v2/guide/computed.html#Watchers).
The idea here is to create a computed value with getter and setter to facilitate a simplified one-way data flow.
Vue.component('my-input', {
template: `<div><b>My Input:</b> <br>localValue: {{ localValue }} <br><input v-model="localValue"></div>`,
props: ['value'],
computed: {
localValue: {
get () {
return this.value
},
set (value) {
this.$emit('input', value)
}
}
}
})
new Vue({
el: '#app',
data: () => ({
parentValue: 'Inital value'
}),
methods: {
change () {
this.parentValue = 'Changed value'
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.3/vue.min.js"></script>
<div id="app">
<my-input v-model="parentValue"></my-input>
<button @click="change">Change</button><br>
parentValue: {{ parentValue }}
</div>
Upvotes: 13
Reputation: 891
How to pass complex objects to child component (potentially down a few layers):
Parent component:
<child v-model='parentEntity' />
Child component:
model: {
prop: 'modelValue',
event: 'update:modelValue',
},
props: {
modelValue: {
type: Object,
required: true,
},
},
...
entity: {
// getter
get() {
return Object.assign({}, this.modelValue);
},
// setter
set(newValue) {
this.$emit('update:modelValue', newValue);
},
},
...
Upvotes: 1