0

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() {

});
0stone0
  • 34,288
  • 4
  • 39
  • 64
  • You will have to add the event to your `li` created upon creation, and perhaps store a list of them so you can go on over any them at any of the clicks events and mark them withe appropriate classes. What have you tried yourself? – somethinghere Aug 29 '23 at 15:09

3 Answers3

0

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>
0stone0
  • 34,288
  • 4
  • 39
  • 64
0

You can provide the string to search for and then modify array with Array#filter based on the provided string.

// 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 searchfor = "drank";

const addProducts = (array, element, key) => {
    array
    .filter(({group}) => new RegExp(`${key}`).test(group))
    .forEach(item => {
        const li = document.createElement('li');
        li.textContent = item.name;
        element.appendChild(li);
    });
}

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

You can also filter based on user input in several ways:

// 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, str) => {
    array
    .filter(({group}) => new RegExp(`${str}`).test(group))
    .forEach(item => {
        const li = document.createElement('li');
        li.textContent = item.name;
        element.appendChild(li);
    });
}

addProducts(products, list, '');

$('button.search').on('click', function(e) {
    e.preventDefault();
    $('#productList').empty();
    const str = $(this).data("x"); console.log( str );
    addProducts(products, list, str);
});

$('input.search').on('keyup', function(e) {
    e.preventDefault();
    $('#productList').empty();
    const str = this.value; console.log( str );
    addProducts(products, list, str);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul id='productList'></ul>

<button class="search" data-x="warme">warme</button>
<button class="search" data-x="drank">drank</button>
<button class="search" data-x="koude">koude</button>
<button class="search" data-x="">All</button>
<br>
Search for: <input class="search" type="text">
PeterKA
  • 24,158
  • 5
  • 26
  • 48
-1

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);
});

// 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>

  
Nicolas
  • 8,077
  • 4
  • 21
  • 51
  • Hello Nicolas, I used your method because i just wanna load the products when the group is clicked. Now i have the following problem: When you clicked the #warme-dranken button the frond-end shows the products but you can't go back to all products. And the second problem is that the function also have to work on the others buttons with id #koude-dranken, #friet and # snacks. So i think i have to make and if and else statement and a loop that check witch button is clicked. I hope that you can help me – Nicky Wiesbrock Aug 30 '23 at 09:23
  • You can apply the same principle for the other type of beverages, simply replace the predicate accordingly. If you want to show all the products, you can use the default predicate. – Nicolas Aug 30 '23 at 12:33
  • As a side note, since you are passing the list to the `addProducts` function, you could simply filter the list to show the appropriate items, then pass the filtered list to the `addProducts` function. In retrospect, it make more sens that way. – Nicolas Aug 30 '23 at 12:34