Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

593
Views
In Vue JS, how do I add a class to an element inside my v-for loop when clicked on, without it being added to each looped element?

Hope the question made some sense. I'm using Vue JS and I have few elements being looped using v-for. Inside each block of elements being looped, is a button along with a div. In this case my loop runs three times. That means I get three buttons in each looped block of code, along with those three div's.

When I click on one of the three buttons I would like for the div in that block to receive a class dynamically. However, as it stands, when I click on one of the three buttons, the class is being added, but it is being added to all three looped div elements inside the loop.

How can I get the current looped div to only receive the specific class when the related button is clicked on, without the other two div's from the loop receiving it also?

Here is my code so far with what I have tried myself:

<template>
    <div v-for="(todo, index) in todos" :key="index" class="relative">
        <button @click="showDiv">
            show div
        </button>
        <div :class="appear" class="absolute bg-red-500">
            <p>{{ todo.text }}</p>
        </div>
    </div>
</template>

<script>
    import {defineComponent} from 'vue'
    export default defineComponent({
        data() {
            return {
                appear: 'left-0',
                todos: [
                    { text: 'Learn Laravel' },
                    { text: 'Learn Vue JS' },
                    { text: 'Learn Tailwind CSS' },
                ]
            }
        },
        methods: {
            showDiv() {
                this.appear = 'left-2/4';
            }
        }
    })
</script>
over 4 years ago · Santiago Trujillo
3 answers
Answer question

0

This is happening because you have all of your code running at the same "level" (or scope to be more technical), thus the DOM "thinks" all of the elements are supposed to get the class added to it. You can solve this problem easily by simply creating a new component for repetitive bits of code (like when you need a for loop) and by making use of Vue's slots (https://vuejs.org/v2/guide/components-slots.html) feature.

// corresponding example JS file or section (depending on your setup) for TodoListItem
export default {
  name: 'TodoListItem',
  props: {
    todo: { type: Object, requried: true } 
  },
  data() {
    return { 
      isClicked: false 
    }
  },
  methods: {
    toggleIsClicked() {
      this.isClicked = !this.isClicked;
    },
  },
};
<!-- index.html -->
<todo-list>
  <todo-list-item
    v-for="(todo, index) in todos"
    :key="index"
    :todo="todo"
  ></todo-list-item>
</todo-list>

<!-- TodoList.vue -->
<template>
  <div class="todo-container">
    <slot></slot>
  </div>
</template>

<!-- TodoListItem.vue -->
<!-- Don't forget to set your props in the corresponding component JS file or else your TodoListItem.vue won't know about the todo object you are passing down to it. -->
<!-- You will also need to move your @click handler here too in the methods section -->
<template>
  <div class="relative">
    <button @click="showDiv">show div</button>
    <div :class="appear" class="absolute bg-red-500">
      <p>{{ todo.text }}</p>
    </div>
  </div>
</template>

I hope this helps my friend!

over 4 years ago · Santiago Trujillo Report

0

The reason is that you are using one variable appear to manage the state of all the buttons, instead you can maintain seperate booleans called visible for each of the items

Check the below working example

var app = new Vue({
        el: "#app",
        data() {
            return {
                appear: 'left-0',
                
                /*** Change added to below array ***/
                
                todos: [
                    { text: 'Learn Laravel', visible: false },
                    { text: 'Learn Vue JS', visible: false },
                    { text: 'Learn Tailwind CSS', visible: false },
                ]
            }
        },
        /** Changes added below **/
        computed: {
         getButtonText() {
          return ind => {
           return this.todos[ind].visible ? 'hide div': 'show div';
          }
         },
         getClass() {
           return ind => {
             return this.todos[ind].visible ? 'left-2/4': 'absolute bg-red-500';
           }
         }
        },
        methods: {
            showDiv(index) {
                this.todos[index].visible = !this.todos[index].visible; // Change added
            }
        }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
    <div v-for="(todo, index) in todos" :key="index" class="relative">
        <button @click="showDiv(index)">
           {{getButtonText(index)}} <!-- Change added -->
        </button>
        <div :class="getClass(index)"> <!-- Change added -->
            <p>{{ todo.text }}</p>
        </div>
    </div>
</div>

over 4 years ago · Santiago Trujillo Report

0

add a boolean field in your array and use that field as a condition for the dynamic class e.g

                { text: 'Learn Laravel', isLeft: false },
                { text: 'Learn Vue JS', isLeft: false },
                { text: 'Learn Tailwind CSS', isLeft: false },

Now on click, just toggle the isLeft field and use it as a condition to dynamic class

<div v-for="(todo, index) in todos" :key="index" class="relative">
    <button @click="todo.isLeft = !todo.isLeft">
        show div
    </button>
    <div :class="{'left-2/4': todo.isLeft}" class="absolute bg-red-500">
        <p>{{ todo.text }}</p>
    </div>
</div>                
over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!