Reputation: 171
I'm trying to show a card with extra information for each card inside a v-for loop.
<template>
<div v-for="card in cards">
<card>
<!-- card content with information -->
<button @click="viewExtra" />
</card>
<card v-if="card.infoExtra && showExtra>
<!-- card content with extra information -->
</card>
</div>
</template>
<script>
export default {
data: () => ({
cards: [] // Array with cards and information
,showExtra: false
}),
methods: {
viewExtra() {
this.showExtra = !this.showExtra;
}
}
</script>
It should only show extra card if principal card contains extra information (card.infoExtra) but it's showing for all cards that have infoExtra, not for the one on which I click the button.
Here's what I've done so far:
What am I doing wrong.
Thanks in advance.
Upvotes: 1
Views: 2181
Reputation: 767
Here is a better approach to your question which doesn't require any methods and covers multiple scenarios.
<div v-for="(card, index) in cards" :key="index">
<card>
<!-- card content with information -->
<button @click="showExtraIndex = showExtraIndex === index && showExtraIndex !== null ? null : index" />
</card>
<card v-if="card.infoExtra && showExtraIndex === index">
<!-- card content with extra information -->
</card>
</div>
<script>
export default {
data: () => ({
cards: [] // Array with cards and information
showExtraIndex: null
}),
}
</script>
Code explanation:
[MOST IMPORTANT] You must use :key
while using v-for
which acts as a unique id for each item of the array.
Assign the index
of the for loop to the variable showExtraIndex
on click of showExtra button if the value of showExtraIndex
is null. Once the value is assigned, it will fulfill the condition added to the below card showing extrainfo, and on clicking the same button back, it will assign null
value to the variable showExtraIndex
eventually hiding the extrainfo card.
Upvotes: 1
Reputation: 27192
My understanding was wrong, No need to add a separate property in each object as each card component will contains their own scope and render separately. Hence, single variable showExtra
will work perfectly.
Here is the live Demo :
Vue.component('card', {
data() {
return {
showExtra: false
}
},
template: `
<div class="card">
<p>{{ cardinfo }}</p>
<button @click="viewExtra">View Extra</button>
<p v-if="extrainfo && showExtra">
{{ extrainfo }}
</p>
</div>
`,
props: ['cardinfo', 'extrainfo'],
methods: {
viewExtra() {
this.showExtra = !this.showExtra;
}
}
});
new Vue({
el: '#container',
data: {
cards: [{
id: 1,
cardInfo: 'This is the content for Card 1',
infoExtra: 'Extra infor for Card 1'
}, {
id: 2,
cardInfo: 'This is the content for Card 2',
infoExtra: 'Extra infor for Card 2'
}, {
id: 3,
cardInfo: 'This is the content for Card 3',
infoExtra: 'Extra infor for Card 3'
}, {
id: 4,
cardInfo: 'This is the content for Card 4',
infoExtra: 'Extra infor for Card 4'
}]
}
});
#container {
display: flex;
flex-direction: row;
flex-wrap: wrap;
margin: auto;
background: grey;
width: 750px;
opacity: .5;
border-radius: 3px;
margin-top: 50px;
padding: 10px;
}
.card {
width: 20%;
height: 180px;
align-self: center;
background: whitesmoke;
padding: 5px;
border-radius: 3px;
margin: 10px 10px;
font-family: monospace;
transition: all .15s ease-in-out;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.10/vue.min.js"></script>
<main id="container">
<card v-for="card in cards" :key="card.id"
:cardinfo="card.cardInfo" :extrainfo="card.infoExtra">
</card>
</main>
Upvotes: 1
Reputation: 1848
Since you have mutual showExtra
state when you toggle it to true, all cards will show extra information.
You should have had showExtra
state for individual for each card
async created() {
try {
const response = await this.$api.getCard()
this.cards = [...response?.data?.map(i => ({
showExtra: false, // attach state for each card, initially to false
...i,
}))]
} catch (err) {
// do something
}
}
<template>
<div v-for="card in cards">
<card>
<!-- card content with information -->
<button @click="card.showExtra = true" /> <!-- toggle it -->
</card>
<card v-if="card.infoExtra && card.showExtra>
<!-- card content with extra information -->
</card>
</div>
</template>
Upvotes: 0