-1

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>

3
  • I'd consider searching for "js filter by two conditions" (or sort, etc) as a decent starting point, maybe with "site:stackoverflow.com" for more specificity. Commented Apr 24, 2023 at 16:39
  • 1
    just some instead of every? But definitely a duplicate Commented Apr 24, 2023 at 16:40
  • Does this answer your question? Filter Array of Objects based on checkboxes Commented Apr 24, 2023 at 16:44

2 Answers 2

0

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>

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

Comments

0

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>

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.