JavaScript's array.filter method is an array method you've likely heard of, read about or even used while following a few tutorials or solving javascript algorithm questions. It's a very important array method you'll use a lot.
The array.filter method...
Takes an array
Takes a filter condition
Loops over the array
Checks for array elements that satisfy the filter condition and passes those elements into a new array
Leaves the original array intact
If this is your first time reading about the filter method then check MDN's detailed explanation or this equally explanatory article on FreeCodeCamp.
If this is your first time checking out the Visualizing JavaScript Series then check out Article Zero of this series.
What we'll be building
You'll visualize the array.filter method by making product category filter buttons for product list of some yummy cakes.
The product section will have buttons that filter items shown on the screen based on their categories. This is a common feature on ecommerce websites and you'll learn how to make a simplified version of it using JavaScript
You've read a brief explanation of the array.filter() method and you've seen what you'll be making, now, let's get started.
Creating the filter Buttons
I'll start the project by copying the HTML from the array.map article but I'll make a few modifications to the code.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div class="btn-container">
<button class="filter-all" type="button" data-id="all">All</button>
<button class="filter-btn" type="button" data-id="cakes">Cakes</button>
<button class="filter-btn" type="button" data-id="cup-cakes">
Cupcakes
</button>
<button class="filter-btn" type="button" data-id="wedding">
Wedding
</button>
</div>
<div class="section-center">
<article>
<img src="/assets/Doughnuts.jpg" alt="" />
<div class="item-info">
<div class="item-div">
<h2 class="item">buttermilk pancakes</h2>
<h4 class="item-price">$15</h4>
</div>
<p class="item-desc">
Lorem ipsum dolor sit amet consectetur, adipisicing elit.
Reprehenderit at tenetur ratione eaque.
</p>
</div>
</article>
</div>
<script src="app.js"></script>
</body>
</html>
The changes made to the original code are:
Created a
div
withclass
ofbtn-container
for the filter buttons.Added four buttons to the container and gave them classes of
filter-btn
andfilter-all
.Added a
data-id
to eachbutton
to serve as a unique identifier,data-id
allows HTML elements to be used in unique ways. You'll see a bit more of this later in the article.
Styling the filter Buttons
You can just copy and paste the CSS to save some time
@import url('https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,300;0,500;1,200&display=swap');
*{
margin: 0;
padding: 0;
text-decoration: none;
font-family: Poppins;
}
body{
display: flex;
flex-direction: column;
justify-content: center;
align-items:center ;
padding-top: 2em;
}
button{
cursor: pointer;
background-color: red;
color: white;
height: 50px;
width: 100px;
border: none;
padding: 2px;
font-weight: bold;
font-size: 1em;
border-radius: 5%;
}
button:hover{
background-color: white;
border: 2px solid red;
color: red;
transition: .7s ease;
}
button:focus{
background-color: whitesmoke;
border-bottom: 4px solid red;
color: red;
}
.section-center{
padding: 2em;
display: flex;
justify-content: center;
gap: 20px;
flex-wrap: wrap;
}
h4{
font-size: 1.2em;
}
article{
display: flex;
flex-direction: column;
width: 16em;
box-shadow: 5px 5px 10px 0.1px grey;
margin-bottom: 10px;
border-radius: 3%;
}
img{
max-width: 100%;
border-top-left-radius: 3%;
border-top-right-radius: 3%;
}
.item-info{
padding: .5rem;
display: flex;
flex-direction: column;
gap: 10px;
}
Making the filter buttons Functional
We'll use the javascript code from the array.map article since it contains the array of products and the displayMenuItems
function we need to map over the array and display the products on the screen.
I've edited the product description in the menu array and changed it from the lorem placeholder text to something more readable.
const menu = [
{
id: 1,
title: "Triple layer Cake",
price: "$15.99",
img: "https://unsplash.com/photos/kPxsqUGneXQ",
desc: "Exquisite, moist layers of flavorful cake with delectable fillings. A feast for the senses.",
},
{
id: 2,
title: "Vanilla goodness",
price: "$13.99",
img: "https://unsplash.com/photos/vdx5hPQhXFk",
desc: "A heavenly delight of creamy vanilla perfection. Indulge in pure bliss with every bite.",
},
{
id: 3,
title: "Chocolate cupcake",
price: "$6.99",
img: "https://unsplash.com/photos/6SHd7Q-l1UQ",
desc: "A miniature delight of rich, moist chocolate perfection. Indulge in a moment of pure bliss.",
}]
const section = document.querySelector('.section-center')
function displayMenuItems(){
let displayMenu = menu.map(function(item){
return `
<article>
<img src=${item.img} alt="">
<div class="item-info">
<div class="item-div">
<h2 class="item">${item.title}</h2>
<h4 class="item-price">${item.price}</h4>
</div>
<p class="item-desc">${item.desc}</p>
<button class>${item.btn}</button>
</div>
</article>
`
})
section.innerHTML = displayMenu
}
displayMenuItems()
To make the buttons functional, you need to select the filter buttons using the querySelectorAll
, using the querySelectorAll
method on classes
creates a NodeList
for those classes (you can think of a NodeList
as a mini array grouping the classes) this NodeList
is then assigned to a variable named filterButtons
const filterButtons = document.querySelectorAll(".filter-btn")
The button
classes are in a NodeList
and this list can be looped over using the forEach
array method shown below. The forEach
method in the code snippet below goes over the filterButtons
list containing the filter buttons, takes each button on the list and runs a function on that button.
filterButtons.forEach(btn => {
// rest of the code here
})
filterButtons.forEach(btn => {
btn.addEventListener("click", (e) => {
//the rest of the code
}
The code snippet above gives each button
an event listener that takes an event type of click
, giving something an event listener of click
means when it is 'clicked' a function should run.
(e) => {
const category = e.currentTarget.dataset.id
const menuCategory = menu.filter(item => {if(item.category === category){
return item
}})
displayMenuItems(menuCategory);
})
The code snippet above does several things but we'll break it into chunks.
const category = e.currentTarget.dataset.id
The function takes an event
e
as an argument ande.currentTarget.dataset.id
checks the fordata-id
of the current button being clicked and assigns thedata-id
to avariable
namedcategory
const menuCategory = menu.filter(item => { if(item.category === category) { return item }})
The
menu.filter
method goes over themenu
array and checks thecategory
of eachitem
of themenu
array using theif
statement.The
if
statement checks if thecategory
of anitem
in themenu
array matches thecategory
of the button clicked (remember we added a click listener to each button), when the correct item is found, themenu.filter
returns the item into a new array calledmenuCategory
.
You can remove the if
statement from the code above and rewrite it as
const menuCategory = menu.filter(item => {
return item.category === category
})
The code still does the same thing but without the need for the if
statement
displayMenuItems(menuCategory)
Finally, we set the array to be mapped over by the
displayMenuItems
function to themenuCategory
array instead of themenu
array.
Making the all
button Functional
You might remember there's a button
with a data-id
of all
, the all
button is meant to display all the products in the array, the easiest way to do this is to pass the menu
array back into the displayMenuItems
function.
You can do this in just two steps.
Select the
all
button
using aquerySelector
const filterAll = document.querySelector(".filter-all")
Add a
click
event listener that runs a function, the function passes themenu
array(the original array) back into thedisplayMenuItems
function that displays all the products.filterAll.addEventListener("click", () => { displayMenuItems(menu) })
This resets the page to its original state with all the products displayed.
You can see the complete code below.
const section = document.querySelector(".section-center"); const filterButtons = document.querySelectorAll(".filter-btn") const filterAll = document.querySelector(".filter-all") const menu = [ { id: 1, title: "Triple layer Cake", category: "cakes", price: "$15.99", img: "https://unsplash.com/photos/kPxsqUGneXQ", desc: "Exquisite, moist layers of flavorful cake with delectable fillings. A feast for the senses." }, { id: 2, title: "Vanilla goodness", category: "wedding", price: "$13.99", img: "https://unsplash.com/photos/vdx5hPQhXFk", desc: "A heavenly delight of creamy vanilla perfection. Indulge in pure bliss with every bite." }, { id: 3, title: "Chocolate cupcake", category: "cup-cakes", price: "$6.99", img: "https://unsplash.com/photos/6SHd7Q-l1UQ", desc: "A miniature delight of rich, moist chocolate perfection. Indulge in a moment of pure bliss." }, ]; filterButtons.forEach(btn => { btn.addEventListener("click", (e) => { const category = e.currentTarget.dataset.id const menuCategory = menu.filter(item => { return item.category === category }) displayMenuItems(menuCategory); }) }) filterAll.addEventListener("click", () => { displayMenuItems(menu) }) function displayMenuItems(menuItems) { let displayMenu = menuItems.map(function (item) { return ` <article data-id="${item.id}"> <img src=${item.img} alt=""> <div class="item-info"> <div class="item-div"> <h2 class="item">${item.title}</h2> <h4 class="item-price">${item.price}</h4> </div> <p class="item-desc">${item.desc}</p> </div> </article> `; }); section.innerHTML = displayMenu.join(''); } displayMenuItems(menu);
Conclusion
You have visualized the array.filter
method by building functional product category filter buttons for a product list, you've used some javascript syntax like the forEach
array method, addEventListener
, and the if
statement to build the project.
You have also briefly heard of a NodeList
, you can read more about NodeList on MDN
Please practice a bit more and try rebuilding the entire project from scratch so you can get a better grip on it. If you have any questions, comments or suggestions, feel free to drop them in the comments or reach out to me on Twitter where I'm more active. See you in the next article