EDIT: Check out this repository that I created for easier parsing.
I have developed a Component that displays products in a datatable. The first column of the table contains a link that triggers a modal displaying a form specific to the product that was clicked (using its ID). To style and design my components, I am utilizing the PrimeVue library.
<template>
<Column field="id" headerStyle="width: 5%">
<template #body="slotProps">
<ProductForm :product="slotProps.data" :show="showModal(slotProps.data.id)" />
<a href="#" @click.stop="toggleModal(slotProps.data.id)">
<span class="pi pi-external-link"> </span>
</a>
</template>
</Column>
</template>
<script>
import ProductForm from "./forms/ProductForm";
export default {
data() {
return {
activeModal: 0,
}
},
components: { ProductForm },
methods: {
toggleModal: function (id) {
if (this.activeModal !== 0) {
this.activeModal = 0;
return false;
}
this.activeModal = id;
},
showModal: function (id) {
return this.activeModal === id;
},
},
</script>
The modal is actually nested within the ProductForm component (I created a template for the Modal for reusability). So essentially, there are three components in play (ProductList -> ProductForm -> BaseModal). Here's the structure of the product form:
<template>
<div>
<BaseModal :show="show" :header="product.name">
<span class="p-float-label">
<InputText id="name" type="text" :value="product.name">
<label for="name">Product</label>
</span>
</BaseModal>
</div>
</template>
<script>
import BaseModal from "../_modals/BaseModal";
export default {
props: ["product", "show"],
components: { BaseModal },
data() {
return {};
},
};
</script>
When the modal pops up, it utilizes the ProductForm subcomponent. Below is the structure of the BaseModal component:
<template>
<div>
<Dialog :header="header" :visible.sync="show" :modal="true" :closable="true" @hide="doit">
<slot />
</Dialog>
</div>
</template>
<script>
export default {
props: {
show: Boolean,
header: String,
},
methods: {
doit: function () {
let currentShow = this.show;
this.$emit("showModel", currentShow)
},
},
data() {
return {
};
},
};
</script>
I am passing the product
object and a show
boolean which determines the visibility of the modal all the way down through the components (from ProductList to ProductForm and finally to BaseModal). The modal being used is a PrimeVue component called Dialog
. In this component, there is a property named "closable" that allows the modal to be closed using an X button when clicked, triggered by the hide
event. Everything seems to be functioning correctly as expected apart from needing to click another modal link twice before it opens after the initial click.
The main issue arises when attempting to close a modal, resulting in the error message: "Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "show"". I have tried various approaches like emitting events and updating the original prop's value but the error persists (even with the existing code). Perhaps due to the depth of nesting reaching three components deep, my attempts are unsuccessful. As a newcomer to working with props, slots, and $emit, I understand that I may be making fundamental mistakes in my implementation. Additionally, structuring components at such a level of depth might also be contributing to the problem. What could I be overlooking?