I'm trying to control the visibility of a child component from the parent using a prop.
My child component has a visible
prop. To avoid mutating the visible
prop I assigned it to a local isVisible
ref, and I'm using that to conditionally show and hide a form.
But when I try to hide the form using a button with @click="isVisible = false"
nothing happens, and I get a console error saying Set operation on key "visible" failed: target is readonly
.
It's also confusing why the error messsage is referring to the visible
prop because I am using the local isVisible
variable instead.
This is the ChildForm.vue
(child component):
<template>
<q-form v-if="isVisible">
<q-input v-model="modelValue" />
<q-btn label="Hide The Form" @click="isVisible = false" />
</q-form>
</template>
<script setup lang="ts">
import { ref, toRef } from 'vue';
const props = defineProps({
visible: {
type: Boolean,
required: true,
default: false,
},
});
const isVisible = toRef(props, 'visible');
const modelValue = ref('');
</script>
This is the ParentPage.vue
(parent component):
<template>
<child-form :visible="showForm" />
<q-btn label="Show the Form" @click="showForm = true" />
</template>
<script setup lang="ts">
import { ref } from 'vue';
import ChildForm from 'src/components/ChildForm.vue';
const showForm = ref(false);
</script>
toRef()
retains the reactive connection to the original source, so modifying isVisible
effectively modifies the original prop, which is supposed to be readonly, leading to the warning you observed.
But I think you're actually trying to keep the child's visible
prop in sync with the parent's showForm
prop, such that updates in the child are automatically reflected in the parent. v-model
is the tool for that problem.
In the parent, bind showForm
to v-model:visible
:
<child-form v-model:visible="showForm">
In the child, emit an update:visible
event with the desired value whenever you want to update the parent:
<template>
<q-form v-if="visible">
<q-input v-model="modelValue" /> 👇
<q-btn label="Hide The Form" @click="$emit('update:visible', false)" />
</q-form>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const props = defineProps({
visible: {
type: Boolean,
required: true,
default: false,
},
})
const modelValue = ref('')
</script>