I'm facing an issue with my custom input component in my app where I need to emit change events up to the parent and send those values to the $store using commit/dispatch. While debugging, I observed that the parent can receive the values but I am puzzled by this error message:
[Vue warn]: Error in v-on handler: "TypeError: Cannot read properties of undefined (reading 'value')"
found in
---> <CustomInput>
This error only occurs when a user is manually editing the title/subtitle fields and shows up after every keystroke. Could this be a timing error?
Custom Input Component:
<template>
<div>
<label for="title">Edit Title: </label>
<input
type="text"
id="title"
:updateTitle="updateTitle"
v-model="inputTitle"
/>
<label for="subtitle">Edit Subtitle: </label>
<input
type="text"
id="subtitle"
:updateSubtitle="updateSubtitle"
v-model="inputSubtitle"
/>
</div>
</template>
<script>
export default {
name: 'CustomInput',
props: {
value: {
type: Object,
required: true,
},
},
computed: {
updateTitle() {
console.log('updateTitle: ', this.value.title);
return this.value.title;
},
updateSubtitle() {
console.log('updateSubtitle: ', this.value.subtitle);
return this.value.subtitle;
},
inputTitle: {
get() {
return this.value.title;
},
set(title) {
console.log('setting new title: ', title);
this.$emit('input', title);
},
},
inputSubtitle: {
get() {
return this.value.subtitle;
},
set(subtitle) {
console.log('setting new subtitle: ', subtitle);
this.$emit('input', subtitle);
},
},
},
};
</script>
Parent Component:
<template>
<main class="home-page page">
<div v-if="!editMode" class="display-information">
<div class="title">
<span class="bold">Title: </span>{{title}}
</div>
<div class="subtitle">
<span class="bold">Subtitle: </span>{{subtitle}}
</div>
<div class="controls">
<button id="randomize-button" class="control-button" @click="randomizeTitleAndSubtitle">
Randomize
</button>
<button id="edit-button" class="control-button" @click="onEdit">Edit</button>
</div>
</div>
<div v-else class="edit-controls">
<CustomInput
:value="{ title, subtitle }"
@input="onSave(v = { title, subtitle }, $event.target.value)"
/>
<div class="controls">
<button id="cancel-button" class="control-button" @click="onCancel">Cancel</button>
<button id="save-button" class="control-button" @click="onSave">Save</button>
</div>
</div>
</main>
</template>
<script>
import CustomInput from '@/components/CustomInput.vue';
import { mapState, mapActions } from 'vuex';
export default {
name: 'Home',
components: {
CustomInput,
},
data() {
return {
editMode: false,
};
},
computed: {
...mapState(['title', 'subtitle']),
},
methods: {
...mapActions(['randomizeTitleAndSubtitle', 'updateTitleAndSubtitle']),
onEdit() {
this.editMode = true;
},
onCancel() {
this.editMode = false;
},
onSave(v) {
this.editMode = false;
console.log('returned value object: ', v);
this.$store.dispatch('UPDATE_TITLE', v.title);
this.$store.dispatch('UPDATE_SUBTITE', v.subtitle);
},
},
mounted() {
this.randomizeTitleAndSubtitle();
},
};
</script>