0

I have a <ul> of items
Then I have an array of classes to filter.
Now I want to loop through all <li> and show only the items that contain all of the classes in the array and hide all the others.

How can I do that?

Code so far (untested):

JS

define([
    "jquery"
], function($){
    "use strict";

    function main(config, element) {

        $('.filter-option').on('change', function (event) {

            const activeFilters = $('.filter-option:checked');

            if (!activeFilters) {
                $('.product').forEach(function(item) {
                    item.show();
                });
            } else {
                $('.product').forEach(function(item) {
                    //if item has all classes from activeFilters id's show else hide
                });
            }
        });
    }
    return main;
});

HTML

<div class="filter-box">
    <h3>Size</h3>
    <input type="checkbox" class="filter-option" id="size-s" name="size-s">
    <label for="size-s" class="filter-option-label">Small</label>
    <input type="checkbox" class="filter-option" id="size-m" name="size-m">
    <label for="size-m" class="filter-option-label">Medium</label>
    <input type="checkbox" class="filter-option" id="size-l" name="size-l">
    <label for="size-l" class="filter-option-label">Large</label>
    <h3>Colour</h3>
    <input type="checkbox" class="filter-option" id="color-white" name="color-white">
    <label for="color-white" class="filter-option-label">White</label>
    <input type="checkbox" class="filter-option" id="color-red" name="color-red">
    <label for="color-red" class="filter-option-label">Red</label>
    <input type="checkbox" class="filter-option" id="color-blue" name="color-blue">
    <label for="color-blue" class="filter-option-label">Blue</label>
</div>
<ul id="product-list">
    <li class="product color-red size-l">Red Large</li>
    <li class="product color-red size-m">Red Medium</li>
    <li class="product color-red size-s">Red Small</li>
    <li class="product color-blue size-l">Blue Large</li>
    <li class="product color-blue size-m">Blue Medium</li>
    <li class="product color-blue size-s">Blue Small</li>
    <li class="product color-white size-l">White Large</li>
    <li class="product color-white size-m">White Medium</li>
    <li class="product color-white size-s">White Small</li>
</ul>
2
  • Please show us all relevant code, Html, css, jquery. Commented Sep 1, 2020 at 9:07
  • included my code Commented Sep 1, 2020 at 9:52

4 Answers 4

1

Assuming that you have something like this and want a VanillaJS solution:

<div id="list-container">
    <ul>
        <li class="example">One</li>
        <li class="example another-class">Two</li>
        <li class="example">Three</li>
        <li class="example">Four</li>
        <li class="example">Five</li>
    </ul>
</div>

You can iterate the <li> elements and check the classes like this:

// Required classes array
let reqClasses = ['example', 'another-class'];

// Function to check if the element has the required classes
const hasClasses = (item) => {
   var s = true;
   
   reqClasses.forEach((classname) => {
      if (!item.classList.contains(classname) && s) {
         s = false;
      }
   });
  
   return s;
}

// We get the <li> elements
let list = document
   .getElementById("list-container")
   .querySelectorAll('li');

// We call the function on each element and toggle visibility depending on the return
list.forEach((item) => {
   if (!hasClasses(item)) {
      item.style.display = 'none';
   }
});
Sign up to request clarification or add additional context in comments.

4 Comments

You are missing a ) in the last forEach. Second, when I run your code it hides all the li
@Carsten you're right, I updated the source with the proper one.
Wouldn't it be possible to drop the 's' and just iterate through the required classes and return false as soon as one doesn't fit? Since I need all classes to match? Also would it be possible to just: 1. hide everything 2. jQuery Select everything with all required classes 3. show selection I'll try your code though, thanks!
Ended up with this, which is based on your answer: jsfiddle.net/Chazlol/mqg851tc/3
1

Solved it like this now:

Update: Had to adjust the filters from AND to OR.
For that the accepted answer was the most helpful.
Still think this approach is suitable for what I initially wanted to do,
so I'll keep it here in case someone else finds it to be helpful.

For the inital question

"How to check if element has all classes in array"

and with using jQuery, a simple solution would be:

  1. Loop through array of classes and concatenate them to a string.
  2. Select that string with jQuery
  3. Returns only matching elements

$('.filter-option').on('change', function (event) {
  const activeFilters = $('.filter-option:checked');
  let classString = "";
  
  if (activeFilters.length === 0) {
    $('.product').show();
  } else {
    $('.product').hide();
    activeFilters.each((index, filter) => {
      classString += "." + filter.id;
    });
    $(classString).show();
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="filter-box">
    <h3>Size</h3>
    <input type="checkbox" class="filter-option" id="size-s" name="size-s">
    <label for="size-s" class="filter-option-label">Small</label>
    <input type="checkbox" class="filter-option" id="size-m" name="size-m">
    <label for="size-m" class="filter-option-label">Medium</label>
    <input type="checkbox" class="filter-option" id="size-l" name="size-l">
    <label for="size-l" class="filter-option-label">Large</label>
    <h3>Colour</h3>
    <input type="checkbox" class="filter-option" id="color-white" name="color-white">
    <label for="color-white" class="filter-option-label">White</label>
    <input type="checkbox" class="filter-option" id="color-red" name="color-red">
    <label for="color-red" class="filter-option-label">Red</label>
    <input type="checkbox" class="filter-option" id="color-blue" name="color-blue">
    <label for="color-blue" class="filter-option-label">Blue</label>
</div>
<ul id="product-list">
    <li class="product color-red size-l">Red Large</li>
    <li class="product color-red size-m">Red Medium</li>
    <li class="product color-red size-s">Red Small</li>
    <li class="product color-blue size-l">Blue Large</li>
    <li class="product color-blue size-m">Blue Medium</li>
    <li class="product color-blue size-s">Blue Small</li>
    <li class="product color-white size-l">White Large</li>
    <li class="product color-white size-m">White Medium</li>
    <li class="product color-white size-s">White Small</li>
</ul>

Fiddle: https://jsfiddle.net/Chazlol/3zuaey0x/1/

Comments

0

You are probably better serverd by using <input type "radio"> elements "radio buttons" instead of inpout type="checkbox"> elements, as these will only allow one of the same-named elements to be checked. The script for making elements visible or invisible is then straightforward:

const ul=document.querySelector('#product-list');
document.querySelector('.filter-box').onchange=ev=>{
  let siz=document.querySelector('[name=size]:checked');
  let col=document.querySelector('[name=colour]:checked');
  [...ul.children].filter(li=>
     li.style.display= siz&&li.classList.contains(siz.value)
                    && col&&li.classList.contains(col.value) ? 'block': 'none' 
  );
}
<div class="filter-box">
    <h3>Size</h3>
    <label><input type="radio" name="size" value="size-s">small</label>
    <label><input type="radio" name="size" value="size-m">medium</label>
    <label><input type="radio" name="size" value="size-l">large</label>
    <h3>Colour</h3>
    <label><input type="radio" name="colour" value="color-white">white</label>
    <label><input type="radio" name="colour" value="color-red">red</label>
    <label><input type="radio" name="colour" value="color-blue">blue</label>
</div>

<ul id="product-list">
    <li class="product color-red size-l">Red Large</li>
    <li class="product color-red size-m">Red Medium</li>
    <li class="product color-red size-s">Red Small</li>
    <li class="product color-blue size-l">Blue Large</li>
    <li class="product color-blue size-m">Blue Medium</li>
    <li class="product color-blue size-s">Blue Small</li>
    <li class="product color-white size-l">White Large</li>
    <li class="product color-white size-m">White Medium</li>
    <li class="product color-white size-s">White Small</li>
</ul>

Comments

-1

You can use a combination of Array.prototype.every() and JQuery .hasClass()

const classList = ['a', 'b'];

function checkClassList($el, classList){
  return classList.every((c) => $el.hasClass(c));
}

console.log(checkClassList($("#id1"), classList))
console.log(checkClassList($("#id2"), classList))
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul id="id1" class="a b"></ul>
<ul id="id2" class="a"></ul>

Comments

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.