0π
I found two problems with your example that might throw this off.
-
The use of
v-model
directly to the property. Usev-bind
instead to have it only display. And usev-on:change
handler to fire the$emit('update:propertyname', value)
and send the new value to update on the object. -
The value sent along in the
$emit
seems empty and thus makes no change. Use$event.target.value
instead.
Side note: v-on:keyup
might not be the best event to listen to, since input can also be drag-and-dropped. Listening to v-on:change
would be beter in that case.
Note on event listeners when using only v-bind.sync
instead of v-bind:propertyName.sync
:
If you want to listen to the update:propertyName
event from the child component on the parent, you have to use the .capture
modifier. Otherwise the update
event is caught by the v-on:update:propertyName
on the child component and this does not bubble up to the parent.
So you can use v-on:update:name.capture="someMethod"
on the <oslo>
tag for example. And have this someMethod
in the parentβs methods
. After this is called, the event will be triggered on the child component which will update the object and thereby the property.
All together:
let Oslo = {
props: {
name: String,
access: String
},
name: 'Oslo',
template: `<div>
<input type="text" :value="name" @change="$emit('update:name', $event.target.value)" />
<input type="text" :value="access" @change="$emit('update:access', $event.target.value)" />
</div>`
}
new Vue({
el: "#app",
components: {
Oslo,
},
data: {
thedata: {
name: 'Oslo name',
access: 'admin'
}
},
methods: {
nameWillBeUpdated: function(v) {
console.log('New value of name will be:', v);
// After this, the `update:name` event handler of the
// child component is triggered and the value will change.
},
},
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script>
<div id="app">
<span>{{this.thedata.name}} - {{this.thedata.access}}</span>
<oslo
v-bind.sync="thedata"
v-on:update:name.capture="nameWillBeUpdated"
/>
</div>
0π
You can just pass an object and sync it instead of individual properties if you have many properties to listen to from child component. See the example below:
Vue.config.productionTip = false
Vue.config.devtools = false
Vue.component('Oslo', {
template: `
<div>
<input type="text" v-model="comp_name" @keyup="$emit('update:name', comp_name)" />
<input type="text" v-model="comp_access" @keyup="$emit('update:access', comp_access)" />
</div>
`,
props: {
data: {
name: String,
access: String,
}
},
data() {
return {
comp_name: this.data.name,
comp_access: this.data.access
}
}
})
new Vue({
el: '#app',
data() {
return {
doc: {
name: 'Oslo name',
access: 'admin'
}
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div>
<span>---- {{ this.doc.name }}----</span>
<span>---- {{ this.doc.access }}----</span>
<oslo :data="this.doc" v-bind.sync="doc" />
</div>
</div>