skip to Main Content

I’m new to using this site, not sure if I need to edit my original question or if starting a new one is the appropiate way of doing things.

Anyway, I got some help yesterday with filtering using Javascript. Thanks again to those who helped me out. I tried to add another filter (price), along with modifying the javascript, but it’s not working. The Color and Size work like they’re suppose to, but I wanted to add another category, "price", to also aid in drilling-down the filtering.

  1. What I’m trying to do it have the user select one or all the Colors and have those products displayed. If no Color is choosen then display all the products.
    (That is already working)

  2. Then when/if they choose a Size or multiple Sizes, only show the products in the Colors from #1 AND the sizes chosen. If no Color is chosen then only show products with the choosen Size.
    (That is already working)

  3. Now I’m trying to include another category called Price but I can’t get it working. So I’m trying to use #1 and #2 filtering to include a drill-down for price. As an example; if Color and Size is not chosen, then it will only show products with the checked Price. If Green and $20 is chosen, then it will not show any products. If no Color is selected, Medium and Large are selected, and $20 is selected, it will only show Product C.

I hope that clarifies what I’m trying to do. If anyone can help, that would be greatly appreciated!

const filterCheckboxes = document.querySelectorAll('.filter-checkbox');
const colorCheckboxes = document.querySelectorAll('.color-checkbox');
const sizeCheckboxes = document.querySelectorAll('.size-checkbox');
const priceCheckboxes = document.querySelectorAll('.price-checkbox');
const filterables = document.querySelectorAll('.filterable');

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

  const sizeChecked = Array.from(sizeCheckboxes)
    .filter(checkbox => checkbox.checked)
    .map(checkbox => checkbox.value);

  const priceChecked = Array.from(priceCheckboxes)
    .filter(checkbox => checkbox.checked)
    .map(checkbox => checkbox.value);

  if (!(colorChecked.length || sizeChecked.length || priceChecked.length)) {
    filterables.forEach(filterable => {
      filterable.style.display = 'block';
    })
    return;
  }

  filterables.forEach(filterable => {
    const colors = filterable.dataset.colors.split(' ');
    if (colorChecked.length >= 1 && sizeChecked.length >= 1 && priceChecked.length >= 2) {
      if (colorChecked.includes(colors[0]) && sizeChecked.includes(colors[1]) && priceChecked.includes(colors[2])) {
        filterable.style.display = 'block';
      } else {
        filterable.style.display = 'none';
      }
    } else {
      if (colorChecked.includes(colors[0]) || sizeChecked.includes(colors[1]) || priceChecked.includes(colors[2])) {
        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 color-checkbox" value="red">Red</label>
  <label><input type="checkbox" class="filter-checkbox color-checkbox" value="green">Green</label>
  <label><input type="checkbox" class="filter-checkbox color-checkbox" value="blue">Blue</label>
</div>
<div>
  <h3>Size</h3>
  <label><input type="checkbox" class="filter-checkbox size-checkbox" value="small">Small</label>
  <label><input type="checkbox" class="filter-checkbox size-checkbox" value="medium">Medium</label><label>
    <input type="checkbox" class="filter-checkbox size-checkbox" value="large">Large</label>
</div>
<div>
  <h3>Price</h3>
  <label><input type="checkbox" class="filter-checkbox price-checkbox" value="10">$10</label>
  <label><input type="checkbox" class="filter-checkbox price-checkbox" value="20">$20</label><label>
    <input type="checkbox" class="filter-checkbox price-checkbox" value="30">$30</label>
</div>
<div>
  <br>
  <hr>
  <h1>Filtered Result</h1>
  <div class="filterable" data-colors="blue large 30">Product A</div>
  <div class="filterable" data-colors="green small 10">Product B</div>
  <div class="filterable" data-colors="red medium 20">Product C</div>
  <div class="filterable" data-colors="red large 30">Product D</div>
</div>

2

Answers


  1. You missed it in the selector. It should be document.querySelectorAll('.price-checkbox');

    const filterCheckboxes = document.querySelectorAll('.filter-checkbox');
        const colorCheckboxes = document.querySelectorAll('.color-checkbox');
        const sizeCheckboxes = document.querySelectorAll('.size-checkbox');
        const priceCheckboxes = document.querySelectorAll('.price-checkbox');
        const filterables = document.querySelectorAll('.filterable');
    
        function updateFilter() {
          const colorChecked = Array.from(colorCheckboxes)
            .filter(checkbox => checkbox.checked)
            .map(checkbox => checkbox.value);
    
          const sizeChecked = Array.from(sizeCheckboxes)
            .filter(checkbox => checkbox.checked)
            .map(checkbox => checkbox.value);
            
           
            
        const priceChecked = Array.from(priceCheckboxes)
            .filter(checkbox => checkbox.checked)
            .map(checkbox => checkbox.value);
     
          if (!(colorChecked.length || sizeChecked.length || priceChecked.length)) {
            filterables.forEach(filterable => {
              filterable.style.display = 'block';
            })
            return;
          }
    
          filterables.forEach(filterable => {
            const colors = filterable.dataset.colors.split(' ');
            if (colorChecked.length >= 1 && sizeChecked.length >= 1  && priceChecked.length >= 2) {
              if (colorChecked.includes(colors[0]) && sizeChecked.includes(colors[1]) && priceChecked.includes(colors[2])) {
                filterable.style.display = 'block';
              } else {
                filterable.style.display = 'none';
              }
            } else {
              if (colorChecked.includes(colors[0]) || sizeChecked.includes(colors[1]) || priceChecked.includes(colors[2])) {
                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 color-checkbox" value="red">Red</label>
      <label><input type="checkbox" class="filter-checkbox color-checkbox" value="green">Green</label>
      <label><input type="checkbox" class="filter-checkbox color-checkbox" value="blue">Blue</label>
    </div>
    <div>
      <h3>Size</h3>
      <label><input type="checkbox" class="filter-checkbox size-checkbox" value="small">Small</label>
      <label><input type="checkbox" class="filter-checkbox size-checkbox" value="medium">Medium</label><label>
        <input type="checkbox" class="filter-checkbox size-checkbox" value="large">Large</label>
    </div>
    <div>
      <h3>Price</h3>
      <label><input type="checkbox" class="filter-checkbox price-checkbox" value="10">$10</label>
      <label><input type="checkbox" class="filter-checkbox price-checkbox" value="20">$20</label><label>
        <input type="checkbox" class="filter-checkbox price-checkbox" value="30">$30</label>
    </div>
    <div>
        <br>
        <hr>
      <h1>Filtered Result</h1>
      <div class="filterable" data-colors="blue large 30">Product A</div>
      <div class="filterable" data-colors="green small 10">Product B</div>
      <div class="filterable" data-colors="red medium 20">Product C</div>
      <div class="filterable" data-colors="red large 30">Product D</div>
    </div>
    Login or Signup to reply.
  2. This can be shortened so much

    Note I delegate from the nearest static container. Here I wrapped the filters in a div

    Please note every only shows the elements that matches ALL filters. some matches any element that contains a checked filter

    const updateFilter = () => {
      const classes = [...document.querySelectorAll('.filter-checkbox:checked')]
        .map(chk => chk.value);
      document.querySelectorAll('.filterable')
        .forEach(filterable => {
        const filtered = filterable.dataset.colors.split(' ');
        const show = classes.some(cls => filtered.includes(cls))
        console.log(show,filtered.join(','),classes.join(','));
        filterable.hidden = !show;
      })
    };
    document.getElementById("filterDiv").addEventListener("click", updateFilter);
    
    updateFilter(); // initial filter based on default checkbox state
    <div id="filterDiv">
      <div>
        <h3>Color</h3>
        <label><input type="checkbox" class="filter-checkbox color-checkbox" value="red">Red</label>
        <label><input type="checkbox" class="filter-checkbox color-checkbox" value="green">Green</label>
        <label><input type="checkbox" class="filter-checkbox color-checkbox" value="blue">Blue</label>
      </div>
      <div>
        <h3>Size</h3>
        <label><input type="checkbox" class="filter-checkbox size-checkbox" value="small">Small</label>
        <label><input type="checkbox" class="filter-checkbox size-checkbox" value="medium">Medium</label><label>
        <input type="checkbox" class="filter-checkbox size-checkbox" value="large">Large</label>
      </div>
      <div>
        <h3>Price</h3>
        <label><input type="checkbox" class="filter-checkbox price-checkbox" value="10">$10</label>
        <label><input type="checkbox" class="filter-checkbox price-checkbox" value="20">$20</label><label>
        <input type="checkbox" class="filter-checkbox price-checkbox" value="30">$30</label>
      </div>
    </div>
    <div>
      <br>
      <hr>
      <h1>Filtered Result</h1>
      <div class="filterable" data-colors="blue large 30">Product A</div>
      <div class="filterable" data-colors="green small 10">Product B</div>
      <div class="filterable" data-colors="red medium 20">Product C</div>
      <div class="filterable" data-colors="red large 30">Product D</div>
    </div>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search