Search code examples
javascripthtmlfor-loopfilterhtmlcollection

Filtering pizzas by ingredients


I have buttons where you can choose which ingredients to filter

//index.html

<div class="submenu">
    <input type="checkbox" class="filter-item" id="olive" onclick="filter()" />
    <label for="olive">
        <img alt="olive" src="img/png/pizza/olive.png" />
    </label>
    <input type="checkbox" class="filter-item" id="shrimp" onclick="filter()" />
    <label for="shrimp">
        <img alt="shrimp" src="img/png/pizza/shrimp.png" />
    </label>
    <input type="checkbox" class="filter-item" id="mushroom" onclick="filter()" />
    <label for="mushroom">
        <img alt="mushroom" src="img/png/pizza/champion.png" />
    </label>
    <input type="checkbox" class="filter-item" id="pepperoni" onclick="filter()" />
    <label for="pepperoni">
        <img alt="pepperoni" src="img/png/pizza/pepperoni.png" />
    </label>
    <footer id="filter-text">no filter applied</footer>
</div>

And menu items (pizzas)

//index.html

<div class="menu-container">
    <img id="olive-pizza" class="menu-item olive" alt="olive" />
    <img id="pepperoni-pizza" class="menu-item pepperoni" alt="pepperoni" />
    <img id="shrimp pizza" class="menu-item shrimp" alt="shrimp" />
    <img class="menu-item mushroom" alt="mushroom" />
    <img class="menu-item olive pepperoni" alt="olive, pepperoni" />
    <img class="menu-item olive shrimp mushroom" alt="olive, shrimp, mushroom" />
</div>

I want to display all pizzas that include all ingredients selected. For example, if the ingredients olive and shrimp are selected only show pizzas that at least have both those classes.

My idea is to put all selected ingredients in an array itemsToFilter, then compare each item in that array to the classes of each pizza and then display the "remaining" pizzas.

Here is the function:

var itemsToFilter = [];

//HTMLCollections, not arrays
ingredients = document.getElementsByClassName("filter-item"); 
pizzas = document.getElementsByClassName("menu-item");

function filter() {
    for (var i = 0; i < ingredients.length; i++) {
        if (ingredients[i].checked == true) {
            //add checked item to array itemsToFilter
            if (itemsToFilter.includes(ingredients[i].getAttribute("id")) == false) {
                itemsToFilter.push(ingredients[i].getAttribute("id"));
            }
        } else {
            //remove unchecked item from array itemsToFilter
            for (var y = itemsToFilter.length - 1; y >= 0; y--) {
                if (itemsToFilter[y] === ingredients[i].getAttribute("id")) {
                    if (itemsToFilter.includes(ingredients[i].getAttribute("id")) == true) {
                        itemsToFilter.splice(y, 1);
                    }
                }
            }
        }
        //show pizzas with classes that match items in array itemsToFilter
        for (var i = 0; i < pizzas.length; i++) {
            for (y in itemsToFilter) {
                if (pizzas[i].classList.contains(itemsToFilter[y]) == false) {
                    if (pizzas[i].classList.contains("show") == true) {
                        pizzas[i].classList.remove("show");
                    }
                    break;
                } else {
                    pizzas[i].classList.add("show");
                }
            }
        }
    }
}

This works to some degree. It only works on the first ingredient "olive", where it correctly adds the class show, however it doesn't remove the class when the checkbox is unchecked. Other ingredients doesn't even get added to the array itemsToFilter.

Anyone have an approach?


Solution

  • ... I accidentally put the for loop that shows the pizzas inside the for loop that loops through the ingredient buttons. I moved it out one step and also moved the part that removes the show class from the pizzas before the for loop that loops the array itemsToFilter since it wouldnt remove the show class if the array was empty. Thank you all kindly.