1

I have code below for category selection. When a category is selected, it sets its background to green, otherwise the background is gray; this works fine.

What I want to achieve is when I select multiple items, I want it to keep the background green for all selected categories. Is there a way to do this?

<div class="categories" v-for="(category, index) in categories" :key="index" @click="Add( category._id, index)" :class="[isediting && selectedIndex == index ? 'green' : 'gray']">
  {{ category.category_name }}
</div>

<script>
  methods: {
      Add(AddCategory, index) {
        this.AddCategory.push(AddCategory);
        this.selectedIndex = index;
        this.isediting = true;
      },
</script>

<style>
  .green {
    background-color: #41B883;
  }
  
  .gray {
    background-color: #e5e0ed;
  }
</style>
zcoop98
  • 1,604
  • 1
  • 10
  • 18
sara97
  • 101
  • 6

2 Answers2

1

The only major change that needs to be made to accommodate this is to make selectedIndex an array rather than a single value, so that we can hold more than one selection.

Eg.:

  1. Set selectedIndex to an array [] in data()
  2. When clicked, we should push the value onto the array instead of setting it equal
  3. To check if a given index is selected, we use selectedIndex.includes(index) instead of selectedIndex == index

There's one other side effect to allowing multiple selection though, which is adding support for on-click deselection. But this is also fairly simple, we just need to check whether selectedIndex already contains the value in Add(), and if it does, remove it. We can use Array.prototype.splice() to do this.

Here's an interactive version:

new Vue({
  el: '#app',
  data() {
    return {
      selectedIndex: [],
      categories: [{ _id: 0, category_name: 'noodles' }, { _id: 1, category_name: 'pizza' }, { _id: 2, category_name: 'hamburgers' } ],
    }
  },
  methods: {
    Add(AddCategory, index) {
      //Check if item is selected...
      if (this.selectedIndex.includes(index)) 
        this.Remove(index); //If so, remove from selectedIndex
      else
        this.selectedIndex.push(index); //If not, add to selectedIndex
    },
    Remove(index) { //Find index in selectedIndex, and splice out
      this.selectedIndex.splice(this.selectedIndex.indexOf(index),1);
    },
    RemoveAll() { //To deselect all, we empty the selectedIndex array
      this.selectedIndex = [];
    },
  }
});
.green {
  background-color: #41B883;
}

.gray {
  background-color: #e5e0ed;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script>

<div id="app">
  <div v-for="(category, index) in categories" 
    @click="Add( category._id, index)" 
    :class="[selectedIndex.includes(index) ? 'green' : 'gray']"
  >
    {{ category.category_name }}
  </div>
  <br>
  <button @click="RemoveAll">Unselect All</button>
</div>
zcoop98
  • 1,604
  • 1
  • 10
  • 18
  • i know it's too late to comment, your answer was really helpful unless the remove function didn't work properly.. it's not removing the selected index from array – sara97 Jan 03 '21 at 15:45
  • The SO question "[How can I remove a specific item from an array?](https://stackoverflow.com/q/5767325)" is where I looked for help when putting together that removal function, you may find it helpful too. – zcoop98 Jan 05 '21 at 18:06
1

That's because you are doing it based on the index, so the index is unique and also changing on each click. Try a property for each category such as selected and make it false as default. Then in your click function just do this.categories[index].selected = !this.categories[index].selected. After that bind the class to the category.selected value.