0

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.

5
  • If you want to support multiple categories, selectedCategory needs to be an array: read the docs on how to use it properly. Also, that means that the selectedCategory will be an array of strings, so you can't compare booleans against it. Moreover... you have multiple returns in your else statement. That's not going to work. Commented May 4, 2019 at 14:47
  • I think this may help me youtube.com/watch?v=IkymKuIkajE Commented May 4, 2019 at 15:03
  • Also, your data structure is weird. I would say that clubParking, clubToilets and etc should be stored under a separate key for easy filtering, e.g. { clubName: "Club one", facilities: { parking: true, toilets: false, floodLights: true }}. Do you have the choice to change the structure of the data? Commented May 4, 2019 at 15:04
  • I can change the data structure. I did think the way it was is correct based on vuejs.org/v2/guide/list.html Commented May 4, 2019 at 15:12
  • The data structure is fine. I would remove the prefix club though. It is redundant. Commented May 4, 2019 at 15:18

1 Answer 1

1

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>

Sign up to request clarification or add additional context in comments.

6 Comments

your solution definitely works when I change the checkboxes to radio buttons. However, I do need the ability for the user to select multiple options.
The same applies to checkboxes/multiselect, but you would put the field names in an array and then do a [].some or [].every depending on your logic requirements ( and/or).
@Al-76 I added a sample on how to test multiple fields.
Thanks guy for your help. Sorry I'm rather lost with it all. I do appreciate your help though and patient.
That last example is your ticket!
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.