Chaz
Chaz

Reputation: 722

JS/jQuery - Check if element has all classes in array

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>

Upvotes: 0

Views: 1325

Answers (4)

Chaz
Chaz

Reputation: 722

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/

Upvotes: 1

Carsten Massmann
Carsten Massmann

Reputation: 28226

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>

Upvotes: 0

Marc Hern&#225;ndez
Marc Hern&#225;ndez

Reputation: 318

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';
   }
});

Upvotes: 1

Greedo
Greedo

Reputation: 3559

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>

Upvotes: -1

Related Questions