v-model and child components?
I have a form and bind an input using v-model:
<input type="text" name="name" v-model="form.name">
Now I want to extract the input and make it it's own component, how do you then bind the values of the child component to the parents object form.name
?
Solution 1:
As stated in the documentation,
v-model
is syntactic sugar for:
<input v-bind:value="something" v-on:input="something = $event.target.value">
To implement the v-model
directive for a custom component:
- specify a
value
prop for the component - make a computed property with a computed setter for the inner value (since you should not modify the value of a prop from within a component)
- define a
get
method for the computed property which returns thevalue
prop's value - define a
set
method for the computed property which emits aninput
event with the updated value whenever the property changes
Here's a simple example:
Vue.component('my-input', {
template: `
<div>
My Input:
<input v-model="inputVal">
</div>
`,
props: ['value'],
computed: {
inputVal: {
get() {
return this.value;
},
set(val) {
this.$emit('input', val);
}
}
}
})
new Vue({
el: '#app',
data() {
return {
foo: 'bar'
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.3/vue.min.js"></script>
<div id="app">
<!-- using v-model... -->
<my-input v-model="foo"></my-input>
<!-- is the same as this... -->
<my-input :value="foo" @input="foo = $event"></my-input>
{{ foo }}
</div>
Thanks to @kthornbloom for spotting an issue with the previous implementation.
Breaking changes in Vue 3
Per the documentation, there are breaking changes to the v-model implementation in Vue 3:
-
value
->modelValue
-
input
->update:modelValue
Solution 2:
Specify a :value
prop and an @input
event on the child component, then you can use v-model
syntax in the parent component.
Vue 2
MyInput.vue
<template>
<input
:value="value"
@input="$emit('input', $event.target.value)" />
</template>
<script>
export default {
props: ['value']
};
</script>
Screen.vue
<template>
<my-input v-model="name" />
</template>
<script>
import MyInput from './MyInput.vue';
export default {
components: { MyInput },
data: () => ({
name: ''
})
};
</script>
Vue 3
MyInput.vue
<template>
<input
:value="modelValue"
@input="$emit('update:modelValue', $event.target.value)" />
</template>
<script>
export default {
props: ['modelValue']
};
</script>
Screen.vue
<template>
<my-input v-model="name" />
</template>
<script>
import MyInput from './MyInput.vue';
export default {
components: { MyInput },
data: () => ({
name: ''
})
};
</script>