there is the below child component. The props are updated from an input selector in the parent. Why does level: this.globalForm.level not update the child’s level
Parent:
<template>
<div>
<div class=”form-container”>
<select class=”form-control” v-model=”level”>
<option v-for=”level in options” v-bind:key=”level”>{ level }</option>
</select>
<button @click=”submit()”>Create</button>
</div>
<child v-bind:globalForm=”globalForm”/>
</div>
</template>
<script>
inputFiled;
export default {
data() {
return {
level: “”,
globalForm: {
level: “”
},
options: [“level1”, “level2”, “level3”]
};
},
components: {
child
},
methods: {
submit() {
this.globalForm.level = this.level;
}
},
watch: {
level() {
this.globalForm.level = this.level;
}
}
};
</script>
Child:
<template>
<div class=”form-container”>
<option v-for=”level in options” v-bind:key=”level”>{ level }</option>
</div>
</template>
<script>
export default {
props: { globalForm: Object },
data() {
return {
options: [“level1”,”level2”,”level3”,],
level: this.globalForm.level //this does not update the child’s level component
};
}
};
</script>
Solution :
TLDR
level should be a computed property on the child so that you can detect changes in the prop. You are setting level in the data function, so updates to the prop never make it to level.
Below you’ll find a minimal example on what I think you want to achieve.
Vue.config.productionTip = false;
Vue.component(‘parent’, {
template: `
<div class=”parent”>
<b>PARENT</b>
<div class=”form-container”>
<select class=”form-control” v-model=”level”>
<option v-for=”level in options” v-bind:key=”level”>{ level }</option>
</select>
<button @click=”submit()”>Create</button>
</div>
<child v-bind:globalForm=”globalForm”/>
</div>
`,
data: () => ({
level: “”,
globalForm: {
level: “”
},
options: [“level1”, “level2”, “level3”]
}),
methods: {
submit() {
this.globalForm.level = this.level;
}
}
});
Vue.component(‘child’, {
template: `
<div class=”form-container child”>
<p><b>Child</b></p>
Level: { level }
</div>
`,
props: {
globalForm: Object
},
computed: {
level() {
return this.globalForm.level;
}
}
});
new Vue({
el: “#app”
})
.parent {
background-color: darkgray;
padding: .5em;
border: solid 1px black;
}
.child {
background-color: lightgray;
padding: .5em;
border: solid 1px black;
}
<script src=”https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id=”app”>
<parent></parent>
</div>
More Detailed explanation
There are couple of errors on the code that I’ll go through.
In the child component
When initializing the component, this is not available inside the data function, so this.globalForm will be undefined. An error is thrown in the console when reproducing it.
data() {
return {
options: [“level1”,”level2”,”level3”,], // this looks like duplicated code from the parent
level: this.globalForm.level // throws error
};
}
To fix that error, you can get the vm context from the parameters of data But this is not the solution for the question.
data(vm) { // note vm
return {
level: vm.globalForm.level // note vm
};
}
The real problem is that level: this.globalForm.level runs only once, in the component initialization, so level is undefined. When the globalForm prop changes, level has already been initialized and it will not change (data returns a new object so the reference to the prop is lost).
You want convert level to be a computed property so that changes to the prop can be detected and the inner value returned. See code snippet above.