skip to Main Content

I’m new to javascript and have some code that filters products based on color and size. It works great, but I’m wondering if it’s possible to have the javascript also SUBTRACT products based on two filters.

For example; if you check all the color filters it shows all the products, great. But as soon as I check "small" for example, it still shows all the products since it’s using the filters values from Color.

Is there a way to have it only show "Product B", which has a data filter of a color AND small?

Thanks for your help!

    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)) || 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="red">Red</label>
  <label><input type="checkbox" class="filter-checkbox" value="green">Green</label>
  <label><input type="checkbox" class="filter-checkbox" value="blue">Blue</label>
</div>
<div>
  <h3>Size</h3>
  <label><input type="checkbox" class="filter-checkbox" value="small">Small</label>
  <label><input type="checkbox" class="filter-checkbox" value="medium">Medium</label><label>
    <input type="checkbox" class="filter-checkbox" value="large">Large</label>
</div>
<div>
  <h1>Filtered Result</h1>
  <div class="filterable" data-colors="blue large">Product A</div>
  <div class="filterable" data-colors="green small">Product B</div>
  <div class="filterable" data-colors="red medium">Product C</div>
  <div class="filterable" data-colors="red large">Product D</div>
</div>

I was hoping that Javascript can also subtract products based on multiple values.

2

Answers


  1. For it to work as desired, you should better identify what each value is an instance of (either color or size):

    • Give the parent div of a checkbox group a CSS class that names the dimension (color or size)
    • Replace all data-colors attributes by data-color and data-size attributes
    • Perform a separate includes test for color and for size

    Here is how it could be coded:

    const filterables = document.querySelectorAll('.filterable');
    
    function getChecked(dimension) {
        // Only look at the checkboxes that relate to the given dimension
        let checked = document.querySelectorAll(`.${dimension} .filter-checkbox:checked`);
        if (checked.length == 0) checked = document.querySelectorAll(`.${dimension} .filter-checkbox`);
        return Array.from(checked, box => box.value);
    }
    
    function updateFilter() {
      const filterColors = getChecked("color");
      const filterSizes = getChecked("size");
      
      for (const filterable of filterables) {
        const {color, size} = filterable.dataset;
        const match = filterColors.includes(color) && filterSizes.includes(size);
        filterable.style.display = match ? 'block' : 'none';
      }
    }
    
    // You can listen to the change event at the document level
    document.addEventListener('change', updateFilter);
    updateFilter(); // initial filter based on default checkbox state
    h3 { display: inline-block; }
    h1, h3 { margin: 0; } 
    <div class="color">
      <h3>Color</h3>
      <label><input type="checkbox" class="filter-checkbox" value="red">Red</label>
      <label><input type="checkbox" class="filter-checkbox" value="green">Green</label>
      <label><input type="checkbox" class="filter-checkbox" value="blue">Blue</label>
    </div>
    <div class="size">
      <h3>Size</h3>
      <label><input type="checkbox" class="filter-checkbox" value="small">Small</label>
      <label><input type="checkbox" class="filter-checkbox" value="medium">Medium</label>
      <label><input type="checkbox" class="filter-checkbox" value="large">Large</label>
    </div>
    <div>
      <h1>Filtered Result</h1>
      <div class="filterable" data-color="blue" data-size="large">Product A</div>
      <div class="filterable" data-color="green" data-size="small">Product B</div>
      <div class="filterable" data-color="red" data-size="medium">Product C</div>
      <div class="filterable" data-color="red" data-size="large">Product D</div>
    </div>
    Login or Signup to reply.
  2. You have to check if the element has the N filters values, there is a example code:

     <script>
            const filterCheckboxes = document.querySelectorAll('.filter-checkbox');
            const filterables = document.querySelectorAll('.filterable');
            let filters = [];
            //Create a function to handle the check event
            function handleCheck(event) {
                if (event) {
                    //If the box is chjecked, add the value to filters array
                    if (event.target.checked) {
                        filters.push(event.target.value);
                        updateFilteredItems();
                    }
                    //If uncheck the box, remove the value form filters array
                    if (!event.target.checked) {
                        let index = filters.indexOf(event.target.value);
                        if (index != -1) {
                            filters.splice(index, 1);
                            updateFilteredItems();
                        }
                    }
                }
            }
    
            function updateFilteredItems() {
                filterables.forEach(item => {
                    if (filters.length > 0) {
                        // lets check if the item has the filters values
                        let itemValues = item.dataset.colors.split(' ');
                        //Check if the item values are in the filters array
                        if (filters.length > 1) {
                            if (filters.includes(itemValues[0]) && filters.includes(itemValues[1])) {
                                item.style.display = 'block';
                            } else {
                                item.style.display = 'none';
                            }
                        } else {
                            if (filters.includes(itemValues[0]) || filters.includes(itemValues[1])) {
                                item.style.display = 'block';
                            } else {
                                item.style.display = 'none';
                            }
                        }
                    } else {
                        item.style.display = 'block'
                    }
                })
            }
    
            filterCheckboxes.forEach(checkbox => {
                checkbox.addEventListener('change', handleCheck);
            });
    
        </script>
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search