skip to Main Content

Help with modifying the code so I can sort by more than one filter. As an example, I’d like to be able to "check" BOTH Blue and Green, and have the result show two items. My code would work like that IF there is both ‘blue green’ in the data-colors area.

I know very little JavaScript, so any help would be appreciated!

const filterCheckboxes = document.querySelectorAll('.filter-checkbox');
const filterables = document.querySelectorAll('.filterable');

function updateFilter() {
  const checkedValues = Array.from(filterCheckboxes)
    .filter(checkbox => checkbox.checked)
    .map(checkbox => checkbox.value);

  filterables.forEach(filterable => {
    const colors = filterable.dataset.colors.split(' ');
    if (checkedValues.every(value => colors.includes(value))) {
      filterable.style.display = 'block';
    } else {
      filterable.style.display = 'none';
    }
  });
}

filterCheckboxes.forEach(checkbox => {
  checkbox.addEventListener('change', updateFilter);
});

updateFilter(); // initial filter based on default checkbox state
<div>
  <h3>Color</h3>
  <label><input type="checkbox" class="filter-checkbox" value="blue">Blue</label>
  <label><input type="checkbox" class="filter-checkbox" value="green">Green</label>
  <label><input type="checkbox" class="filter-checkbox" value="red">Red</label>
</div>
<div>
  <h1>Filtered Result</h1>
  <div class="filterable" data-colors="blue">Content 1</div>
  <div class="filterable" data-colors="green">Content 2</div>
  <div class="filterable" data-colors="red">Content 3</div>
</div>

2

Answers


  1. I’ve updated yours to include @pilchard suggestion and a clunky reset of the list.

    It needed to utilize some instead of every, then you need to reset you list if no filter was selected.

    <!doctype html>
    <html>
    <head>
    <meta charset="utf-8">
    <title>Untitled Document</title>
    </head>
    
    <body>
    <div>
        <h3>Color</h3>
      <label><input type="checkbox" class="filter-checkbox" value="blue">Blue</label>
      <label><input type="checkbox" class="filter-checkbox" value="green">Green</label>
      <label><input type="checkbox" class="filter-checkbox" value="red">Red</label>
        </div>
       <div>
           <h1>Filtered Result</h1>
    <div class="filterable" data-colors="blue">Blue Content 1</div>
    <div class="filterable" data-colors="green">Green Content 2</div>
    <div class="filterable" data-colors="red">Red Content 3</div>
    </div> 
        <script>
        const filterCheckboxes = document.querySelectorAll('.filter-checkbox');
    const filterables = document.querySelectorAll('.filterable');
    
    function updateFilter() {
      const checkedValues = Array.from(filterCheckboxes)
        .filter(checkbox => checkbox.checked)
        .map(checkbox => checkbox.value);
      
        if (!checkedValues.length > 0) {  
          filterables.forEach(filterable => {
            filterable.style.display = 'block';
          })
        return;
      }
    
      filterables.forEach(filterable => {
        const colors = filterable.dataset.colors.split(' ');
        if (checkedValues.some(value => colors.includes(value))) {
          filterable.style.display = 'block';
        } else {      
          filterable.style.display = 'none';
        }    
      });
      
    
    }
    
    filterCheckboxes.forEach(checkbox => {
      checkbox.addEventListener('change', updateFilter);
    });
    
    updateFilter(); // initial filter based on default checkbox state
    
        </script>
    </body>
    </html>
    Login or Signup to reply.
  2. In the call filterables.forEach(...), making the following in the if condition change solves the problem.
    Change:

    checkedValues.every(value => colors.includes(value))
    

    To:

    checkedValues.some(value => colors.includes(value)) || checkedValues.length === 0
    
    const filterCheckboxes = document.querySelectorAll('.filter-checkbox');
    const filterables = document.querySelectorAll('.filterable');
    
    function updateFilter() {
      const checkedValues = Array.from(filterCheckboxes)
        .filter(checkbox => checkbox.checked)
        .map(checkbox => checkbox.value);
    
      filterables.forEach(filterable => {
        const colors = filterable.dataset.colors.split(' ');
        if (checkedValues.some(value => colors.includes(value)) || checkedValues.length === 0) {
          filterable.style.display = 'block';
        } else {
          filterable.style.display = 'none';
        }
      });
    }
    
    filterCheckboxes.forEach(checkbox => {
      checkbox.addEventListener('change', updateFilter);
    });
    
    updateFilter(); // initial filter based on default checkbox state
    <div>
      <h3>Color</h3>
      <label><input type="checkbox" class="filter-checkbox" value="blue">Blue</label>
      <label><input type="checkbox" class="filter-checkbox" value="green">Green</label>
      <label><input type="checkbox" class="filter-checkbox" value="red">Red</label>
    </div>
    <div>
      <h1>Filtered Result</h1>
      <div class="filterable" data-colors="blue">Content 1</div>
      <div class="filterable" data-colors="green">Content 2</div>
      <div class="filterable" data-colors="red">Content 3</div>
    </div>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search