[Vuejs]-How to filter an Array with Checkboxes items?

0👍

Use computed properties:

computed: {
   filteredItems(){
      if(this.selectedCategory.length == 0) return this.items;
      return this.items.filter(el => {
         for(let i = 0; i < this.selectedCategory.length; i++){
            if(el.categories == this.selectedCategory[i]) return el;
         }
      });

   }
}

Then you go for v-for="item of filteredItems"

I didnt tested it. If you provide me more code i could help you more

0👍

You need to create one-way binding between your CategoryCheckBox component and your ListCard component.

Because you provided separated code when I can not reproduce it to give you a solution based on your own, I suggest this example to explain my solution.

Step One:

You have many ways to CRUD your items using a Plugins or Vuex or global instance, in my example I used global instance in main.js

Vue.prototype.$myArray = ["Books", "Magazines", "Newspaper"];

I assume you created your items data in the ListCards component

Step Two:

You need to add @change event in your checkbox to handle checked and unchecked states. I used static data (Book) for value.

 <label>
<input type="checkbox" value="Books" @change="handleCategory($event)" /> Books

Now, let’s implement handleCategory method, but before that, as we know that Checkbox and ListCards are independents which means we need to define a bus to create event communication between them and this is your issue so we define the bus inside the main.js

Vue.prototype.$bus = new Vue({});

Now we define handleCategory like this :

methods: {
    handleCategory(e) {
      this.$bus.$emit("checkCategory", e);
    }
  }

Step Three:

How can our ListCards listen to this event ?

By call $bus.$on(..) when the component is created ( Hope you know what Vue lifecycle methods mean )

created() {
    this.$bus.$on("checkCategory", e => this.checkCategory(e));
  },

When the user click the check box the component runs handleCategory then runs checkCategory inside ListCard.

Inside my ListCard, I have categories and originalCategories as data

 data() {
    return {
      categories: this.$myArray,
      originalCategories: this.$myArray
    };
  },

and a template :

<ul v-for="(category,index) in categories" :key="index">
      <CategoryItem :categoryName="category" />
    </ul>

and a created method ( lifecycle )

 created() {
    // $bus is a global object to communicate between components
    this.$bus.$on("checkCategory", e => this.checkCategory(e));
  },

and our filtering methods :

 methods: {
    checkCategory(e) {
      let target = e.target;
      let value = e.target.value;

      target.checked
        ? this.filterCatergories(value)
        : (this.categories = this.originalCategories);
    },
    filterCatergories(value) {
      this.categories = this.categories.filter(val => val === value);
    }
  }

What’s important for you is :

this.categories.filter(val => val === value); //will not do nothing
const categories=this.categories.filter(val => val === value); //will update the view.

And you can change the code or make it better and simple.

@Update

You can also use computed properties but because we have a parameter here which is the category name we need get and set.

  computed: {
    filteredItems: {
      get: function() {
        if (this.selectedCategory.length == 0) return this.items;
        return this.items.filter(value => {
          for (const category of this.selectedCategory) {
            if (value == category) return value;
          }
        });
      },
      set: function(category) {
        this.selectedCategory.push(category);
      }
    }
  },
  methods: {
    checkCategory(e) {
      let target = e.target;
      let value = e.target.value;

      target.checked
        ? (this.filteredItems = value)
        : this.selectedCategory.pop(value);
    }
  }

Leave a comment