Michael
Michael

Reputation: 6899

@click within v-for triggers all @click events

When a single @click is triggered from within the v-for the display property in all of the objects within the array is updated, rather than just by index. I only want that element that is click to receive the event and update the display property, not all of them.

<script>
import TransitionExpand from '@/transitions/transition-expand'
import ResourceCard from '@/components/resource-card'

export default {
  components: {
    TransitionExpand,
    ResourceCard
  },
  data () {
    return {
      
    }
  },
  methods: {
    toggle (evt, i) {
      this.status[i].display = !this.status[i].display
    }
  },
  async asyncData ({ app }) {
    const { data } = await app.$axios.get('training_modules')
    const status = Array(data.trainingModules.length).fill({ display: false })

    return {
      modules: data.trainingModules,
      status
    }
  }
}
</script>

<template>
  <div>
    <div class="container px-4 mx-auto mt-16 lg:mt-32">

      <div class="flex flex-wrap mb-20">
        <h1 class="w-full lg:w-1/2 mb-6">Training Modules</h1>
        <p class="w-full lg:w-1/2 leading-7 text-abbey"></p>
      </div>

      <div 
        v-for="(item, i) in modules"
        :key="item.id"
        class="mb-12"
      >
        <div class="flex items-center">
          <h2>{{ item.title }}</h2>
          <img @click="toggle($event, i)" class="ml-auto cursor-pointer" src="@/assets/images/icons/plus.svg" alt="open"> 
        </div>

        
        <TransitionExpand v-show="status[i].display">
          <div class="">
            <p class="mt-6 mb-12">{{ item.description }}</p>
            <div class="flex flex-wrap -m-3">
              <ResourceCard 
                v-for="resource in item.resources"
                :key="resource.id"
                :resource="resource"
              />
            </div>
          </div>
        </TransitionExpand>
      </div>
      
    </div>
    <BaseFooter />
  </div>
</template>

Upvotes: 1

Views: 161

Answers (1)

Dipen Shah
Dipen Shah

Reputation: 26075

Problem is in const status = Array(data.trainingModules.length).fill({ display: false }) code which is filing all array items with the same object which is observable hence change in display property will be applied to all elements in the array as status[0] === status[1].

Use map instead and it will work as expected:

const status = data.trainingModules.map(() => ({ display: false }));

Upvotes: 1

Related Questions