How to highlight selected item with multiple lists to choose from in vue js

Viewed 1527

Im working with Vue js and I have multiple lists rendered but i only want to select(highlight) one element. At the moment multiple items are highlighted with each click. Hope that makes sense. Here is my code snipets below

<template>
 <div>
    <div class='list-group'>
      <a v-for='(product, idx) in adslCapped' class='list-group-item'
         v-on:click='toggleActiveIndex(idx)' 
         :class="{'active': idx == activeIndex}" >
      {{product.name}}
      </a>
    </div>


    <div class='list-group'>
       <a v-for='(product, idx) in fibre' class='list-group-item'
          v-on:click='toggleActiveIndex(idx)' 
          :class="{'active': idx == activeIndex}" >
       {{product.name}} 
       </a>
    </div>
  </div>
</template>

    data: {
      activeIndex: null
    },
    methods: {
       toggleActiveIndex: function(index){
         this.activeIndex = index
       }
    }

So as you can see I have two lists, but when I click on the first item of the first list, then it highlights the first item in both lists. PLease note that these are only code snippets in relation to the issue i'm having.

4 Answers

With your current app structure, if you want only one item to be highlighted among all the lists, you can add another variable which represents the active list.

Then you need to change the condition for the active class and check if the index is the active index AND if the list is the active list.

HTML

<div id="app">
  <div class='list-group'>
  <a v-for='(product, idx) in adslCapped' class='list-group-item'
     v-on:click='toggleActiveIndex(adslCapped, idx)' 
     :class="{'active': idx == activeIndex && adslCapped == activeList}" >
  {{product}}
  </a>
  </div>


  <div class='list-group'>
     <a v-for='(product, idx) in fibre' class='list-group-item'
        v-on:click='toggleActiveIndex(fibre, idx)' 
        :class="{'active': idx == activeIndex && fibre == activeList}" >
     {{product}} 
     </a>
  </div>
</div>

Script

new Vue({
  el: "#app",
  data() {
    return {
      activeIndex: null,
      activeList: null,
      adslCapped: ['a', 'b', 'c'],
      fibre: ['1244', '125215', '02150']
    }
  },
  methods: {
   toggleActiveIndex: function(list,index){
     this.activeIndex = index;
     this.activeList = list;
   }
  },
})

Demo here

Hope it helps!

I know this is overkill for this simple case but you can abstract list into a component, store selected products separately.

Take a look at the example.

var productList = Vue.component('product-list', {
  props: {
    value: Object,
    products: Array
  },
  template: `
<div class="product-list"><a class="ist-group-item" :class="{'active': product.id === value?.id}" @click="selectProduct(product)" :key="product.id" v-for="product in products">{{product.name}}</a></div>`,
  methods: {
    selectProduct(product) {
      this.$emit('input', product)
    }
  }
})

var app = new Vue({
  el: "#app",
  data() {
    return {
      selected1: null,
      selected2: null,
      products: Array(5).fill(0).map((pr, id) => ({
        id: id + 1,
        name: `Product ${id + 1}`
      }))
    }
  },
  mounted() {
    //console.log(this.products)
  },
  methods: {}
});
.product-list {
  border: 1px solid black;
  padding: 5px;
  margin-top: 5px;
}

.ist-group-item {
  display: block;
  transition: all .3s ease-in;
}

.ist-group-item:hover {
  background: lightgray;
}

.ist-group-item.active {
  background: black;
  color: white;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">

  <product-list v-model="selected1" :products="products">
  </product-list>
  <product-list v-model="selected2" :products="products">
  </product-list>

</div>

The issue is that activeIndex is only one variable - which can't be reused for setting the index in the both lists.

The issue is that - you should be able to separate which list you want to activate when clicking within the v-for loop.

new Vue({
  el: "#app",
  data: {
    list1: [{
        name: "Learn JavaScript",
        done: false
      },
      {
        name: "Learn Vue",
        done: false
      },
      {
        name: "Play around in JSFiddle",
        done: true
      },
    ],
    list2: [{
        name: "Learn JavaScript",
        done: false
      },
      {
        name: "Learn Vue",
        done: false
      },
      {
        name: "Play around in JSFiddle",
        done: true
      },
    ],
    active1Index: null,
    active2Index: null
  },
  methods: {
    toggleActive: function(list, index) {
      if (list === "list1") {
        this.active1Index = index
      } else {
        this.active2Index = index
      }
    }
  }
})
body {
  background: #20262E;
  padding: 20px;
  font-family: Helvetica;
}

#app {
  background: #fff;
  border-radius: 4px;
  padding: 20px;
  transition: all 0.2s;
}

li {
  margin: 8px 0;
}

h2 {
  font-weight: bold;
  margin-bottom: 15px;
}

del {
  color: rgba(0, 0, 0, 0.3);
}

.active {
  background: yellow;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>

<div id="app">
  <div class='list-group'>
    <a v-for='(product, idx) in list1' class='list-group-item' v-on:click='toggleActive("list1", idx)' :class="{'active': idx == active1Index}">
      {{product.name}}
      </a>
  </div>


  <div class='list-group'>
    <a v-for='(product, idx) in list2' class='list-group-item' v-on:click='toggleActive("list2", idx)' :class="{'active': idx == active2Index}">
       {{product.name}} 
       </a>
  </div>
</div>

Thanks everyone who answered you guys on stackoverflow are the best. Julia's solution is the one that worked for me.

I have to implement it throughout my whole app and lists now.

Thanks Julia

Related