Search code examples
javascriptjqueryvue.jsv-for

how to toggle class to a single element inside a v-for


I'm new to vueJs and I'm trying to toggle a class "active" to a single element once you clicked on it. Here is my code witch toggle all element with the class material_icons. How to do it to toggle only the element clicked ? thanks. My hmtl :

 <div v-for="(listArtist, index) in listArtists" class="col s4 center" id="art">
<p> {{ listArtist.title_short }}</p>
<p>{{ listArtist.artist.name }} </p>
<p>{{ listArtist.album.title }}</p>
<div id="margin-test">   
    <i class="material-icons" @click="fav(listArtist.title,listArtist.album.title,listArtist.artist.name,listArtist.id)"  v-bind:class="{'active': color}">favorite_border</i>
</div>

my js :

data: {
listArtists:[],
color: false,
}

fav: function(titleTrack, album, artist, id ){
            this.color = !this.color
}

Solution

  • The thing is you currently have only one color flag and multiple artist elements.

    To make it work, you have to find a way of having, instead, multiple colors flags, one for each artist.

    You could do it in basically two forms:

    • You can declare color as an auxiliary object and use id as key (demo 1 below).
      • The same would be achieved by making color an array and using index (of the v-for) instead of id.
      • The advantage of this approach is not to add any properties to your current artist elements.
    • You could also declare a color property in each artist and use it instead (demo 2 below).
      • This is somewhat cleaner, but does require the addition of the color property.

    Demo 1 (using color as a separated object or array)

    new Vue({
      el: '#app',
      data: {
        message: 'Hello Vue.js!',
        listArtists: [
        	{id: 1, title: 'title1', title_short: 'title_short1', artist: {name: 'artist.name1'}, album: {title: 'album.title1'}},
          {id: 2, title: 'title2', title_short: 'title_short2', artist: {name: 'artist.name2'}, album: {title: 'album.title2'}}
        ],
        color: {},
      },
      methods: {
        fav: function(titleTrack, album, artist, id) {
          this.$set(this.color, id, !this.color[id]);
        }
      }
    })
    .active {
      color: red;
    }
    <script src="https://unpkg.com/vue"></script>
    
    <div id="app">
      <div v-for="(listArtist, index) in listArtists" class="col s4 center" id="art">
        <p> {{ listArtist.title_short }}</p>
        <p>{{ listArtist.artist.name }} </p>
        <p>{{ listArtist.album.title }}</p>
        <div id="margin-test">
          <i class="material-icons" @click="fav(listArtist.title,listArtist.album.title,listArtist.artist.name,listArtist.id)" v-bind:class="{'active': color[listArtist.id]}">favorite_border</i>
        </div>
      </div>
    </div>

    Demo 2 (using a color property on each element)

    new Vue({
      el: '#app',
      data: {
        message: 'Hello Vue.js!',
        listArtists: [
        	{id: 1, title: 'title1', title_short: 'title_short1', artist: {name: 'artist.name1'}, album: {title: 'album.title1'}},
          {id: 2, title: 'title2', title_short: 'title_short2', artist: {name: 'artist.name2'}, album: {title: 'album.title2'}}
        ],
        color: {},
      },
      methods: {
        fav: function(titleTrack, album, artist, id, listArtist) {
          this.$set(listArtist, 'color', !listArtist.color);
        }
      }
    })
    .active {
      color: red;
    }
    <script src="https://unpkg.com/vue"></script>
    
    <div id="app">
      <div v-for="(listArtist, index) in listArtists" class="col s4 center" id="art">
        <p> {{ listArtist.title_short }}</p>
        <p>{{ listArtist.artist.name }} </p>
        <p>{{ listArtist.album.title }}</p>
        <div id="margin-test">
          <i class="material-icons" @click="fav(listArtist.title,listArtist.album.title,listArtist.artist.name,listArtist.id,listArtist)" v-bind:class="{'active': listArtist.color}">favorite_border</i>
        </div>
      </div>
    </div>