I am using a card component of vuetify in a loop to display data but when I click on the button present in the card, all buttons of all cards present in the loop open. How can I do so that only the card button I clicked opens?
Here is my template :
<template>
<v-row>
<v-col
v-for="(prop, i) in Object.keys(linkIdeal)"
:key="i"
cols="6"
lg="2"
md="3"
sm="4"
@click="console.log(prop)"
>
<v-card
v-if="linkIdeal[prop].plant_associated[0].category == '1'"
style="z-index: 0"
:
width="100%"
>
<v-img
:src="`${linkIdeal[prop].plant_associated[0].image}`"
width="100%"
height="200"
></v-img>
<v-card-title >
{{ linkIdeal[prop].plant_associated[0].name }}
</v-card-title>
<v-card-actions @click="show = !show" style="cursor: pointer">
<span >Description</span>
<v-spacer></v-spacer>
<v-btn icon>
<v-icon >
{{ show ? 'mdi-chevron-up' : 'mdi-chevron-down' }}
</v-icon>
</v-btn>
</v-card-actions>
<v-expand-transition>
<div v-show="show">
<v-divider></v-divider>
<v-card-text>
<span
v-html="linkIdeal[prop].description"
></span>
</v-card-text>
</div>
</v-expand-transition>
</v-card>
</v-col>
</v-row>
</template>
Here is my script :
import {
mapGetters
} from "vuex";
export default {
props: {},
data: () => ({
linkIdeal: [],
show: false,
}),
computed: {
console: () => console,
...mapGetters({
plantActive: 'permatheque/getPlant',
}),
},
methods: {
async getAssociatedPlant() {
this.$axios.$get('...')
.then(response => {
//this.$store.commit('permatheque/setPlantAssociations', response)
this.linkIdeal = response
console.log(this.linkIdeal)
}).catch(error => {
console.log(error)
});
},
},
mounted() {
this.getAssociatedPlant()
}
}
Thanks for your answer
CodePudding user response:
You are using 1 show
variable as a state for all the cards, their open/close state all depend on that, thus when you toggle this state, all cards act accordingly.
If you want to have an open/close state for every single card, then you should add it to each one (like in their own component) OR you can track the opened cards (e.g. by ID) in an array. Both could be a solution to your problem. (snippet coming to demonstrate)
OPEN/CLOSE STATE TRACKED IN AN ARRAY
Vue.component('ToggleCard', {
props: ['id', 'label', 'open'],
methods: {
onClick() {
this.$emit("update:open")
}
},
template: `
<div
:
@click="onClick"
>
{{ label }} - {{ open }}
</div>
`
})
new Vue({
el: "#app",
data() {
return {
openedCards: [],
cards: [{
id: 0,
label: "CARD 1",
},
{
id: 1,
label: "CARD 2",
},
{
id: 2,
label: "CARD 3",
},
]
}
},
methods: {
isOpen(id) {
return this.openedCards.includes(id)
},
updateOpenedCards(id) {
if (this.isOpen(id)) {
this.openedCards = this.openedCards.filter(cardId => cardId !== id)
} else {
this.openedCards = [...this.openedCards, id]
}
}
},
template: `
<div>
<toggle-card
v-for="card in cards"
:key="card.id"
:id="card.id"
:label="card.label"
:open="isOpen(card.id)"
@update:open="() => updateOpenedCards(card.id)"
></toggle-card>
</div>
`
})
.cursor-pointer {
cursor: pointer;
}
.open {
background: green;
color: white;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app"></div>
OPEN/CLOSE STATE TRACKED IN AN SEPARATE COMPONENTS
Vue.component('ToggleCard', {
props: ['id', 'label'],
data() {
return {
open: false,
}
},
template: `
<div
:
@click="open = !open"
>
{{ label }} - {{ open }}
</div>
`
})
new Vue({
el: "#app",
data() {
return {
cards: [{
id: 0,
label: "CARD 1",
},
{
id: 1,
label: "CARD 2",
},
{
id: 2,
label: "CARD 3",
},
]
}
},
template: `
<div>
<toggle-card
v-for="card in cards"
:key="card.id"
:id="card.id"
:label="card.label"
></toggle-card>
</div>
`
})
.cursor-pointer {
cursor: pointer;
}
.open {
background: green;
color: white;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app"></div>