Al-76
Al-76

Reputation: 1868

How can I filter a VueJS loop by using checkboxes to show different results?

I am having trouble with applying filters whilst using checkboxes to a list of results and need some help.

Currently, only the 'All' option seems to apply any filtering logic.

My HTML containing my filters and loop is as follows:

<div class="container" id="clubs">
    <div class="filter">
        <label><input type="checkbox" v-model="selectedCategory" value="All" /> All</label>
        <label><input type="checkbox" v-model="selectedCategory" value="Parking" /> Parking</label>
        <label><input type="checkbox" v-model="selectedCategory" value="Toilets" /> Toilets</label>
        <label><input type="checkbox" v-model="selectedCategory" value="Floodlights" /> Floodlights</label>
    </div>

    <ul class="clubs-list">
        <li v-for="club in filteredClubs">{{ club.clubName }}</li>
    </ul>
</div> 

Then, the code inside my VueJS app is as below:

var vm = new Vue({
    el:  "#clubs",
    data: {
        clubs: [
            { clubName: "Club One", clubParking: true, clubToilets: false, clubFloodlights: true },
            { clubName: "Club Two", clubParking: true, clubToilets: false, clubFloodlights: false },
            { clubName: "Club Three", clubParking: false, clubToilets: true, clubFloodlights: true },
        ],
        selectedCategory: "All"
    },
    computed: {
        filteredClubs: function() {
            var vm = this;
            var category = vm.selectedCategory;

            if(category === "All") {
                return vm.clubs;
            } else {
                return vm.clubs.filter(function(club) {
                    return club.clubParking === category;
                });
            }
        }
    }
});

Any help welcome as I have been stuck for hours.

Upvotes: 0

Views: 94

Answers (1)

Steven Spungin
Steven Spungin

Reputation: 29081

You need to update your filter to check the category, then filter on the field.

return vm.clubs.filter(function(club) {
  switch(category){
     case 'Toilets':
      return club.clubToilets;
     case 'Parking':
      return club.clubParking;
     // etc...
  }
});

You can refactor this a bit by setting a field name.

return vm.clubs.filter(function(club) {
  let fname;
  switch(category){
     case 'Toilets':
      fname ='clubToilets';
     case 'Parking':
      fname = 'clubParking';
     // etc...
  }
  return club[fname]
});

You can also simply have the value of the select be your field name and use it directly. This may restrict you from additional logic however.

<label><input type="checkbox" v-model="selectedCategory" value="clubParking" /> Parking</label>
return vm.clubs.filter(function(club) {
  return club[category];
}

The bottom line is the category must be mapped to a field name in your object.

For multiple items:

// Map the field names depending on your checkbox values. `selectedCategory` should be an array.

const selectedFieldNames =  selectedCategory.map(category=>{
      switch(category){
         case 'Toilets':
          return 'clubToilets';
         case 'Parking':
          return 'clubParking';
         // etc...
      }
})

// selectedFieldNames now contains the names of your object fields

// This will now return all items that have all those fields set to 'true'
return vm.clubs.filter(function(club) {
  return selectedFieldNames.every(fname=>club[fname])
}

Working Example Based On Your Posted Code.

Note: This really could use some cleaning up, but I left it in a format that you can compare your work and ours.

var vm = new Vue({
	el: "#clubs",
	data: {
		clubs: [
			{
				clubName: "Club One",
				clubParking: true,
				clubToilets: false,
				clubFloodlights: true
			},
			{
				clubName: "Club Two",
				clubParking: true,
				clubToilets: false,
				clubFloodlights: false
			},
			{
				clubName: "Club Three",
				clubParking: false,
				clubToilets: true,
				clubFloodlights: true
			}
		],
		selectedCategory: []
	},
	computed: {
		filteredClubs: function() {
			var vm = this;
			var categories = vm.selectedCategory;
      
			if (categories.includes("All")) {
				return vm.clubs;
			} else {
				const selectedFieldNames = categories.map(category => {
					switch (category) {
						case "ClubToilets":
							return "clubToilets";
						case "ClubParking":
							return "clubParking";
						case "ClubFloodlights":
							return "clubFloodlights";
					}
				});

				return vm.clubs.filter(function(club) {
					return selectedFieldNames.every(fname=>club[fname])
				})			
			}
		}
	}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div class="container" id="clubs">
	<div class="filter">
		<label><input type="checkbox" v-model="selectedCategory" value="All" /> All</label>
		<label><input type="checkbox" v-model="selectedCategory" value="ClubParking" /> Parking</label>
		<label><input type="checkbox" v-model="selectedCategory" value="ClubToilets" /> Toilets</label>
		<label><input type="checkbox" v-model="selectedCategory" value="ClubFloodlights" /> Floodlights</label>
	</div>
	
	<ul class="clubs-list">
		<li v-for="club in filteredClubs">{{ club.clubName }}</li>
	</ul>
</div>

Upvotes: 1

Related Questions