Reputation: 77
I am encountering a problem with multiple default objects sharing the same state, and I am unable to separate the binding. I need to manage the state for each instance independently. The parent and child components pass data to each other, and both communicate directly with the store.
The issue is that when clicking on the 'Add' button in the parent component creates a new row in the child component and adds a default objects (el-input and el-select) to an array, then all the elements are changed to the same state and are not independent.
I am using Vue 3, Pinia for store management, and Element Plus for UI components.
Parent -
<template>
<div>
<!-- first table-->
<el-row>
<div class="first-control-buttons">
<div>
<label class="first-label">First</label>
</div>
<div class="actions-control">
<div class="left-actions-control">
<el-radio-group v-model="store.firstRadio" class="ml-4">
<el-radio label="or" size="small">OR</el-radio>
<el-radio label="and" size="small">AND</el-radio>
</el-radio-group>
</div>
<div class="vertical-divider"></div>
<div class="right-actions-control">
<el-button :icon="Delete" circle @click="removeAllClick('firstCards')"/>
<el-button :icon="Plus" circle @click="store.addCard('firstCards')" />
</div>
</div>
</div>
</el-row>
<childTable :cards="store.firstCards" typeOfCard="firstCards"
@removeCard="store.removeCard"></childTable>
<!-- second table-->
<el-row>
<div class="first-control-buttons">
<div>
<label class="include-exclude-label">Second</label>
</div>
<div class="actions-control">
<div class="left-actions-control">
<el-radio-group v-model="store.secondRadio" class="ml-4">
<el-radio label="or" size="small">OR</el-radio>
<el-radio label="and" size="small">AND</el-radio>
</el-radio-group>
</div>
<div class="vertical-divider"></div>
<div class="right-actions-control">
<el-button :icon="Delete" circle @click="removeAllClick('secondCards')"/>
<el-button :icon="Plus" circle @click="store.addCard('secondCards')"/>
</div>
</div>
</div>
</el-row>
<childTable :cards="store.secondCards"
typeOfCard="secondCards" @removeCard="store.removeCard">
</childTable>
</div>
</template>
<script lang="ts" setup>
import {ref, computed, watch, onMounted} from 'vue'
import { Plus, Delete } from '@element-plus/icons-vue'
import childTable from './childTable.ce.vue';
import {useStore} from "../../../stores/useStore";
const store = useStore();
function removeAllClick(typeOfCards: string) {
if (store.firstCards && typeOfCards === "firstCards") {
ElMessageBox.confirm(`Are you sure you wish to empty?`,'Confirmation', {
}).then(() => {
store.firstCards = []
}).catch(() => {
console.log("cancel button was pressed")
})
} else if (store.secondCards && typeOfCards === "secondCards") {
ElMessageBox.confirm(`Are you sure you wish to empty`,'Confirmation', {
}).then(() => {
store.secondCards = []
}).catch(() => {
console.log("cancel button was pressed")
})
}
}
</script>
Child -
<template>
<el-row>
<div class="internal-form-details">
<div class="top-inputs-internal">
<table style="width: 100%">
<thead>
<tr>
<th>Type</th>
<th>Name</th>
<th>Action</th>
<th>Rule</th>
</tr>
</thead>
<tbody>
<tr v-for="(card, index) in cards" :key="index">
<td>
<el-select
v-model="store.typeOptionValue"
class="m-2 select-box">
<el-option
v-for="item in typeOptions"
:key="item.value"
:label="item.label"
:value="item.value"/>
</el-select>
</td>
<td>
<SharedSelect
placeholder="Select"
:selectAllOption="true"
:typeOption="store.typeOptionValue">
</SharedSelect>
</td>
<td>
<el-select
v-model="store.freqAndVeloValue"
class="m-2 select-box velocity">
<el-option
v-for="item in freqAndVeloOptions"
:key="item.value"
:label="item.label"
:value="item.value"/>
</el-select>
</td>
<td>
<div class="internal-rule-column">
<!-- if Freq -->
<div
v-if="store.freqAndVeloValue === 'freq'"
class="internal-frequency-inputs">
<el-input
v-model="store.freqValue"
@input="validateNumberInput"
type="number"
min="0"
class="frequency-value"/>
<span>or more times</span>
<el-select
v-model="store.freqTimeValue"
class="m-2 time-select">
<el-option
v-for="item in freqTimeOptions"
:key="item.value"
:label="item.label"
:value="item.value"/>
</el-select>
<el-select
v-if="store.freqTimeValue === 'inTheLast'"
v-model="store.freqTimePeriodValue"
class="m-2 time-period-select">
<el-option
v-for="item in freqTimePeriodOptions"
:key="item.value"
:label="item.label"
:value="item.value"/>
</el-select>
</div>
<!-- if Vel -->
<div v-else class="internal-velocity-inputs">
<span>spanning</span>
<el-input
v-model="store.veloValue"
@input="validateNumberInput"
type="number"
min="0"
class="velocity-value"
/>
<span>days</span>
<el-select
v-model="store.veloIncreasedAndDecreasedValue"
class="m-2 select-box increased"
:popper-append-to-body="false"
>
<el-option
v-for="item in veloTimeOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
<span>by</span>
<el-input
v-model="store.veloNumberValue"
@input="validateNumberInput"
type="number"
min="0"
class="velocity-number-value"
/>
<span>% or more</span>
</div>
<div class="remove-button-row">
<el-button :icon="Delete" circle @click="removeCards(index, typeOfCard)"/>
</div>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</el-row>
</template>
<script lang="ts" setup>
import {onMounted, ref, onUnmounted, watch, computed} from "vue";
import {useStore} from "@/stores/useStore";
import SharedSelect from "../../shared/SharedSelect.ce.vue";
const store = useStore();
const defaults = defineProps({
typeOfCard: {
type: String,
default: "",
},
cards: {
type: Array,
default: [],
},
});
onMounted(() => {
const foundObject = typeOptions.find((option) => option.value === store.typeOptionValue).url;
store.fetchTypeOptionValues(foundObject);
});
watch(() => store.typeOptionValue, () => {
const foundObject = typeOptions.find((option) => option.value === store.typeOptionValue).url;
store.fetchTypeOptionValues(foundObject);
})
const emit = defineEmits(["removeCard"]);
const removeCards = (index, typeOfCard) => {
emit("removeCard", {index, typeOfCard});
};
</script>
Store -
import { defineStore } from "pinia";
export const useStore = defineStore({
id: "Yehu",
state: () => ({
firstRadio: "or",
secondRadio: "or",
input: "",
cards: [],
firstCards: [],
secondCards: [],
drawer: false,
dataTable: [],
freqValue: 1,
veloValue: 7,
typeOptionValue: "becImpre",
firstSecondValue: "first",
freqAndVeloValue: "freq",
veloNumberValue: 1,
freqTimeValue: "atAnyTime",
freqTimePeriodValue: "minutes",
veloIncreasedAndDecreasedValue: "increased",
}),
getters: {},
actions: {
addCard(typeOfCard?: string) {
const cardDefaultValues = {
firstSecondValue: "include",
typeOptionValue: "becImpre",
freqAndVeloValue: "freq",
freqValue: 1,
freqTimeValue: "atAnyTime",
veloValue: 7,
veloIncreasedAndDecreasedValue: "increased",
veloNumberValue: 1,
};
if (typeOfCard === "firstCards") {
this.firstCards.push({
...cardDefaultValues,
key: this.firstCards.length + 1,
});
} else if (typeOfCard === "secondCards") {
this.secondCards.push({
...cardDefaultValues,
key: this.secondCards.length + 1,
});
} else {
this.cards.push({
...cardDefaultValues,
key: this.cards.length + 1,
});
}
},
removeCard(props: object) {
if (this.firstCards && props.typeOfCard === "firstCards") {
this.firstCards.splice(props.index, 1);
} else if (this.secondCards && props.typeOfCard === "secondCards") {
this.secondCards.splice(props.index, 1);
} else {
this.cards.splice(props.index, 1);
}
},
},
});
Upvotes: 0
Views: 1116
Reputation: 77
After verifying the things, I found that I needed to use 'card' inside my component because I am iterating through an array that I am passing from the parent component.
Upvotes: 0