Reputation: 5345
I have the following Vue component:
Vue.component('result', {
props: ['stuff'],
data: () => ({}),
template: "<img :src='tag' class='result'></img>",
computed: {
tag: function tag() {
return `pages/search/img/${this.stuff.type.toLowerCase()}_tag.png`;
}
}
});
When the component is created, an error is thrown:
TypeError: Cannot read property 'toLowerCase' of undefined
at VueComponent.tag
However, when I remove the call to toLowerCase()
, the method executes properly, generating a string with the expected type. I could work around this by changing my filenames to have capital letters, but I would rather understand why Vue is behaving this way. Why would a property be undefined only when methods are called on it?
Update: after some troubleshooting, I found that this.stuff.type
is undefined the first time tag()
is computed. Calling toLowerCase()
just forces an error on an otherwise silent bug. Is there a reason the props
aren't defined when computed
functions are called for the first time? Should I be writing my component differently?
Upvotes: 5
Views: 3385
Reputation: 26791
The stuff
prop is undefined when the result
component is created.
There are two options to fix this problem:
Either use the v-if
directive in the parent component's template to make sure stuff
has a value when the result
component is created:
<template>
<result v-if="stuff" :stuff="stuff" />
</template>
Or handle the stuff
prop being undefined
in the result
component.
Vue.component('result', {
props: {
// Object with a default value
stuff: {
type: Object,
// Object or array defaults must be returned from
// a factory function
default: () => ({ type: 'someType'})
},
},
data: () => ({}),
template: "<img :src='tag' class='result' >",
computed: {
tag: function tag() {
return `pages/search/img/${this.stuff.type.toLowerCase()}_tag.png`;
}
}
})
Note: The img
element is a void element, it does not require an end tag.
Upvotes: 4
Reputation: 4666
Props are by default null
but you can give them a default value to overcome this problem.
Example :
Vue.component('result', {
props: {
stuff: {
type: Object,
default: {
type: ''
}
}
},
data: () => ({}),
template: "<img :src='tag' class='result'></img>",
computed: {
tag: function tag() {
return `pages/search/img/${this.stuff.type.toLowerCase()}_tag.png`;
}
}
});
Upvotes: 0