Summer Sale! All accounts are 50% off this week.

matthiascw's avatar

How to toggle class of a specific item in v-for

Hello

I am new to vue and trying to add a class to a specific item in a v-for (list). I am loading some contacts out of the database and just display them as a list of <a>s

Here is my code:

html

<a v-for="contact in contacts" @click="toggleSelected()" >
     <div class="contact" :class="{ 'is-selected': isSelected }">
          <div class="pic-initials">{{ contact.first_name[0] }}{{ contact.last_name[0] }}</div>
          <div class="name">{{ contact.first_name }} {{ contact.last_name }}</div>
          <div class="status"><slot></slot></div>
    </div> 
</a> 

The corresponding click function:

toggleSelected() {
   this.isSelected = ! this.isSelected;
}      

If I click on one item the class is added to every single contact item. How can I toggle it just for one?

Thank you

0 likes
5 replies
Reached's avatar
Reached
Best Answer
Level 11

This is something I have struggled with in the past as well...

Maybe there is a better solution to this, but I think you have to make each of the items a component, then they will have their own scope.

So in your v-for you have this for example:

<a v-for="contact in contacts">
    <contact :contact="contact"></contact>
</a>

Then you have access to all of the same data inside your contact component,

"isSelected" will now have it's own scope if you define it inside the data object in your contact component.

Hope it helps!

1 like
matthiascw's avatar

That worked! Thank you very much Reached.

1 like
superintelligence's avatar

Before finding solution suggested by @reached, I managed to get another one (without subcomponents):

<template>
  <div>
    <div
      v-for="option in options"
      :key="option"
      :class="{ selected: selected_options.includes(option) }"
      @click="toggle_selection_for(option)"
    >
      {{ option }}
    </div>
  </div>
</template>
export default {
  props: ["options"],

  data() {
    return {
      selected_options: [],
    };
  },

  methods: {
    toggle_selection_for(option) {
      if (this.selected_options.includes(option)) {
        this.selected_options = this.selected_options.filter(
          (item) => item !== option
        );
      } else {
        this.selected_options.push(option);
      }
    },
  },
};

This can be useful for somebody, but I actually prefer @reached's solution, as it gives me more fine grained control for select/deselect logic: for example I can $emit two separate user-event on each of event happened.

Please or to participate in this conversation.