Home > Back-end >  How use a button in v-for loop in Nuxt.js?
How use a button in v-for loop in Nuxt.js?

Time:02-24

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>

  • Related