skip to Main Content

I have the following code:

// function loadProducts
const products = [
    { name: 'koffie', price: 2.50, group: 'warme dranken' }, 
    { name: 'thee', price: 2.50, group: 'warme dranken' },
    { name: 'cola', price: 3.50, group: 'koude dranken' },
    { name: 'ice tea', price: 3.50, group: 'koude dranken' },
    { name: 'patat', price: 3.50, group: 'friet' },
    { name: 'patat mayo', price: 3.50, group: 'friet' },
    { name: 'frikandel', price: 3.50, group: 'snacks' },
    { name: 'kroket', price: 3.50, group: 'snacks' }
] 

const list = document.querySelector('#productList');

const addProducts = (array, element) => {
    array.forEach(item => {
        const li = document.createElement('li');
        li.textContent = item.name;
        element.appendChild(li);
    });
}

addProducts(products, list);
<div id='productList'></div>

This code generates a list of products in HTML. Now I want to filter with buttons on the front end and filter on the group string. I know that I have to use filter method but I am stuck on this.

document.getElementById('warme-dranken').addEventListener('click', function() {

});

2

Answers


  1. There are a lot of ways of doing this. Here’s my take on it.

    1. When creating the li‘s, add the data-group to it

      li.dataset.group = item.group;
      
    2. After creating the li‘s, create and call addGroupBoxes that will

    3. In the onchange, I’ve called it onCheckboxToggle, we can

      • Get all the elements where the data-group matches the event value
        const allItemsWithThisGroup = [ ...document.querySelectorAll(`li[data-group="${e.target.name}"]`) ];
        
      • Use the classList to toggle the .hide class that will apply display: none to hide it
        allItemsWithThisGroup.forEach(e => e.classList.toggle('hide'));
        

      If you want the checkboxes to work the other way around, you can change the class or add the class to each item in addProducts

    // function loadProducts
    const products = [
        {name: 'koffie', price: 2.50, group: 'warme dranken', }, 
        {name: 'thee', price: 2.50, group: 'warme dranken', },
        {name: 'cola', price: 3.50, group: 'koude dranken', },
        {name: 'ice tea', price: 3.50, group: 'koude dranken', },
        {name: 'patat', price: 3.50, group: 'friet', },
        {name: 'patat mayo', price: 3.50, group: 'friet', },
        {name: 'frikandel', price: 3.50, group: 'snacks', },
        {name: 'kroket', price: 3.50, group: 'snacks', },
    ];
    
    const list = document.querySelector('#productList');
    
    const addProducts = (array, element) => {
        array.forEach(item => {
            const li = document.createElement('li');
            li.textContent = item.name;
            li.dataset.group = item.group;
            element.appendChild(li);
        });
    }
    
    const addGroupBoxes = (array, element) => {
        const allGroups = [ ...new Set(products.map(p => p.group)) ];
        allGroups.forEach(group => {
            const cb = document.createElement('input');
            cb.name = group;
            cb.type = 'checkbox';
            cb.checked = true;
            cb.onchange = onCheckboxToggle;
            element.appendChild(cb);
            
            const lb = document.createElement('label')
            lb.textContent = group;
            lb.for = group;
            element.appendChild(lb)
        });
    }
    
    const onCheckboxToggle = (e) => {
        const allItemsWithThisGroup = [ ...document.querySelectorAll(`li[data-group="${e.target.name}"]`) ];
        allItemsWithThisGroup.forEach(e => e.classList.toggle('hide'));
    }
    
    addProducts(products, list);
    addGroupBoxes(products, list);
    .hide { display: none; }
    <div id='productList'></div>
    Login or Signup to reply.
  2. You seams to have the base figured out, which is great.

    Now, for the filter part, we are missing a bit of information so it’s hard to produce a complete answer. For example, you want to filter by what property ?

    In any case, you will want to use a if to filter out any product that does not match your filter. This if could be in the forEach function you are already using.

    With that in mind, you could add a parameter to your addProducts function which would contains what we call a "predicate". It’s a function that will be called for each product and used to determine if we want to show it or not.

    Simply put, it would look something like that:

    const addProducts = (array, element, predicate) => {
        array.forEach(item => {
            // we check if the current item should be visible or not
            if(predicate.call(item, item)) {
                const li = document.createElement('li');
                li.textContent = item.name;
                element.appendChild(li);
            }
        });
    }
    
    // the default predicate returns true, to show every item.
    const defaultPredicate = (item) => {
       return true;
    } 
    
    addProducts(products, list, defaultPredicate);
    

    this add the ability to filter the product list if needed. You can use this new ability and call the function with a new predicate parameter, in the click listener of your button:

    document.getElementById('warme-dranken').addEventListener('click', function() {
     const itemOfGroupWarmeDrankenPredicate = function(item) {
       return item.group === "warme draken";
     }
    
     addProducts(products, list, itemOfGroupWarmeDrankenPredicate);
    });
    

    This will add, to the list, only the item of the group warme draken.

    There is a problem, however. Since the list already contain some items, some of them are duplicated. To fix that, we could empty the list first, and then only add the items that match the predicate:

    const emptyProducts = (listNode) =>
       listNode.innerHTML = "";
    }
    
    document.getElementById('warme-dranken').addEventListener('click', function() {
     const itemOfGroupWarmeDrankenPredicate = function(item) {
       return item.group === "warme draken";
     }
    
     emptyProducts(list);
    
     addProducts(products, list, itemOfGroupWarmeDrankenPredicate);
    });
    

    here is a working example

    // function loadProducts
    const products = [
        {
            name: 'koffie', price: 2.50, group: 'warme dranken',
        }, {
            name: 'thee', price: 2.50, group: 'warme dranken',   
        }, {
            name: 'cola', price: 3.50, group: 'koude dranken',   
        }, {
            name: 'ice tea', price: 3.50, group: 'koude dranken',   
        }, {
            name: 'patat', price: 3.50, group: 'friet',   
        }, {
            name: 'patat mayo', price: 3.50, group: 'friet',   
        }, {
            name: 'frikandel', price: 3.50, group: 'snacks',   
        }, {
            name: 'kroket', price: 3.50, group: 'snacks',   
        },
    ];
    
    const list = document.querySelector('#productList');
    
    const addProducts = (array, element, predicate) => {
        array.forEach(item => {
    
            // we check if the current item should be visible or not
            if(predicate.call(this, item)) {
             
                // if so, we add it to the list
                const li = document.createElement('li');
                li.textContent = item.name;
                element.appendChild(li);
            }
        });
    }
    
    // the default predicate returns true, to show every item.
    const defaultPredicate = (item) => {
       return true;
    } 
    
    addProducts(products, list, defaultPredicate);
    
    const emptyProducts = (listNode) => {
        listNode.innerHTML = "";
    }
    
    document.getElementById('warme-dranken').addEventListener('click', function() {
     const itemOfGroupWarmeDrankenPredicate = function(item) {
       return item.group === 'warme dranken';
     }
    
     emptyProducts(list);
    
     addProducts(products, list, itemOfGroupWarmeDrankenPredicate);
    });
    <button id="warme-dranken">alleen warme dranken</button>
    
    <div id='productList'></div>
    
      
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search