I have a parent and child component in Vue 3. I'm using the options (old) API. I am passing data, an object with a bunch of different properties and values, as a prop like this:
/* Parent component */
<template>
...
<child-component :itemData="itemInfo"></child-component>
...
</template>
/* Child Component */
<template>
<input type="checkbox" v-model="itemInfo.isCustomizable">
</template>
<script>
props: {
itemData: Object
}
data() {
return {
itemInfo: this.itemData,
}
}
</script>
When I do this, I get TypeError: Cannot read properties undefined (reading 'isCustomizable')
. Seems like maybe Vue is trying to read itemInfo.isCustomizable
before the prop is fully rendered/loaded in the child component and then assigned to itemInfo
. I'm not using the prop in the checkbox directly because I will need to take the checkbox data and save it in a database, and I know that mutating prop data doesn't fly.
In the past, I've remedied this by creating an empty object in my child component data and put the prop data in a watcher to replace my empty object. Something like:
data() {
return {
itemInfo: {
isCustomizable: 0
}
}
}
...
watch: {
itemData(oldVal, newVal) {
this.itemInfo = newVal;
}
}
But that does not seem to be working anymore, as well as just assigning the itemInfo
data to be the itemData
prop object.
I've run into this issue periodically since I've been using Vue, and although the above approach worked for me, there might be a better way that I don't know about. How do I get around this issue?
CodePudding user response:
1. The most clean solution for your TypeError: Cannot read properties undefined (reading ...)
problem that I know is to use "v-if" on the child component in the template of the parent component. In this way the child gets first rendered after the prop is actually available and its properties can be accessed.
/* Parent component */
<template>
...
<child-component v-if="itemInfo" :itemData="itemInfo"></child-component>
...
</template>
2. An alternative would be to initialize all the data that you need in the parent component.
/* Parent component */
<script>
...
data: {
itemInfo: {
isCustomizable: ''
}
}
...
</script>
CodePudding user response:
Did you try with kebab-case for your prop:
const app = Vue.createApp({
data() {
return {
itemInfo: { isCustomizable: true },
};
},
})
app.component('childComponent', {
template: `
<div>
<input type="checkbox" v-model="itemInfo.isCustomizable">
{{ itemInfo.isCustomizable }}
</div>
`,
props: {
itemData: Object
},
data() {
return {
itemInfo: this.itemData,
}
}
})
app.mount('#demo')
<script src="https://unpkg.com/vue@3"></script>
<div id="demo">
<child-component :item-data="itemInfo"></child-component>
</div>