This content originally appeared on Envato Tuts+ Tutorials and was authored by Jemima Abu
Filtering is a commonly used feature on various webpages. It allows users to narrow down data (like categories, tags, other characteristics) using provided parameters. Let’s create our own!
One common example of on-page filtering would be an eCommerce website that allows users to filter products according to size, color, brand etc.
In this tutorial, we’ll be recreating the Tuts+ author page and implementing a filter component to allow us to filter articles based on their category.
1. Layout and Styling
For this demo, we’ll be cloning the author page so the markup and styling is taken directly from the live site. The main components we’ll be focusing on are the filters and the displayed posts, so we’ll create a <div class="filter-container">
and <div class="posts-container">
and target these in JavaScript.
We’ll style these containers and their content in CSS:
1 |
.posts-container { |
2 |
display: flex; |
3 |
flex-wrap: wrap; |
4 |
}
|
5 |
|
6 |
.post { |
7 |
position: relative; |
8 |
width: 300px; |
9 |
margin-right: 30px; |
10 |
margin-bottom: 40px; |
11 |
border: 1px solid #e1e8ed; |
12 |
border-radius: 4px; |
13 |
margin-top: 13px; |
14 |
min-height: 300px; |
15 |
height: auto; |
16 |
}
|
17 |
|
18 |
.filter-container { |
19 |
display: flex; |
20 |
flex-wrap: wrap; |
21 |
justify-content: flex-start; |
22 |
gap: 10px; |
23 |
padding: 32px 0; |
24 |
border-top: 1px solid #e4e4e4; |
25 |
border-bottom: 1px solid #e4e4e4; |
26 |
margin-bottom: 32px; |
27 |
}
|
28 |
|
29 |
.filter-button { |
30 |
transition: background-color 200ms, color 200ms; |
31 |
background-color: transparent; |
32 |
font: inherit; |
33 |
cursor: pointer; |
34 |
display: inline-block; |
35 |
padding: 0 8px; |
36 |
color: #717171; |
37 |
border: 1px solid #9b9b9b; |
38 |
border-radius: 25px; |
39 |
font-size: 14px; |
40 |
white-space: nowrap; |
41 |
}
|
42 |
|
43 |
.filter-button:hover { |
44 |
background-color: #f3f3f3; |
45 |
color: #3a3a3a; |
46 |
}
|
47 |
|
48 |
.filter-button.is-active { |
49 |
background-color: #0085b6; |
50 |
border-color: #0085b6; |
51 |
color: #fff; |
52 |
}
|
2. Getting Page Data using Fetch API
In this demo, we'll be using the Fetch API to retrieve mock data scraped from the Tuts+ authors page and stored in a Github gist.
Our mock data has the format:
1 |
[
|
2 |
{
|
3 |
"title": "", |
4 |
"link": "", |
5 |
"image": "", |
6 |
"categories": [ ] |
7 |
},
|
8 |
...
|
9 |
]
|
10 |
This is the script for fetching data from the script:
1 |
fetch("https://gist.githubusercontent.com/jemimaabu/b89339c1b7e5f81f8737fb66a858b6fc/raw/cdded4a10dbc98858481b5aedbcce3f3026dc271/tutorials" |
2 |
).then(async (response) => { |
3 |
// handle response data
|
4 |
});
|
Once we’ve gotten our fetched data, we can then manipulate the data and append it on the page.
3. Appending Data to the Webpage
For each object in our fetched response, we’ll create a post div that will display the data on the page. First, let’s define our global variables:
1 |
let postsData = ""; |
2 |
const postsContainer = document.querySelector(".posts-container"); |
Then we’ll create a function createPost()
that will handle appending a new div to the posts-container element. In this function, we create a new div element with the classname post
and set its innerHTML as the data we want to display.
1 |
const createPost = (postData) => { |
2 |
const { title, link, image, categories } = postData; |
3 |
const post = document.createElement("div"); |
4 |
post.className = "post"; |
5 |
post.innerHTML = ` |
6 |
<a class="post-preview" href="${link}" target="_blank"> |
7 |
<img class="post-image" src="${image}"> |
8 |
</a>
|
9 |
<div class="post-content">
|
10 |
<p class="post-title">${title}</p> |
11 |
<div class="post-tags">
|
12 |
${categories |
13 |
.map((category) => { |
14 |
return '<span class="post-tag">' + category + "</span>"; |
15 |
})
|
16 |
.join("")} |
17 |
</div>
|
18 |
</div>
|
19 |
`; |
20 |
|
21 |
postsContainer.append(post); |
22 |
};
|
Inside our post innerHTML, we use the join("")
method on our categories.map()
to remove the ',' symbol that’s included in every array.
Now we can update our response function to call the createPost()
function once the data has been fetched:
1 |
fetch("https://gist.githubusercontent.com/jemimaabu/b89339c1b7e5f81f8737fb66a858b6fc/raw/cdded4a10dbc98858481b5aedbcce3f3026dc271/tutorials" |
2 |
).then(async (response) => { |
3 |
postsData = await response.json(); |
4 |
postsData.map((post) => createPost(post)); |
5 |
});
|
4. Get Filter Params from Response
Since we’re using JavaScript, we can map through our response to create a dynamic list of filter params. Let’s include the global variables for our filter data:
1 |
let filterData = ""; |
2 |
const filterContainer = document.querySelector(".filter-container"); |
Now we want to write a script that sorts through the categories array in each response object and returns a unique list. We can update our response object to handle getting a unique list of filter params
1 |
fetch("https://gist.githubusercontent.com/jemimaabu/b89339c1b7e5f81f8737fb66a858b6fc/raw/cdded4a10dbc98858481b5aedbcce3f3026dc271/tutorials" |
2 |
).then(async (response) => { |
3 |
postsData = await response.json(); |
4 |
postsData.map((post) => createPost(post)); |
5 |
filterData = [ |
6 |
...new Set( |
7 |
postsData
|
8 |
.map((post) => post.categories) |
9 |
.reduce((acc, curVal) => acc.concat(curVal), []) |
10 |
)
|
11 |
];
|
12 |
});
|
Breaking down the code for our filterData:
- We use
[... new Set]
to create an array of unique values. Set returns an object of unique values and the spread syntax [...] converts the object into an array. - We map through the postsData to get the categories array of each post object inside the data response.
- We use the
.reduce()
method to combine the categories array for each post object into one array.
Once we’ve gotten our array of unique filter values from the post categories, we can create a function to append each filter to the page. We’ll create a new button element and set the innerText and className. We’ll also set a “data-state” attribute to handle changing the button state when clicked.
Each filter button will have a click event listener set to the handleButtonClick function, which will be responsible for handling the filtering logic.
1 |
const createFilter = (filter) => { |
2 |
const filterButton = document.createElement("button"); |
3 |
filterButton.className = "filter-button"; |
4 |
filterButton.innerText = filter; |
5 |
filterButton.setAttribute('data-state', 'inactive'); |
6 |
filterButton.addEventListener("click", (e) => |
7 |
handleButtonClick(e, filter) |
8 |
);
|
9 |
|
10 |
filterContainer.append(filterButton); |
11 |
};
|
And update our response function to call the createFilter()
function:
1 |
fetch("https://gist.githubusercontent.com/jemimaabu/b89339c1b7e5f81f8737fb66a858b6fc/raw/cdded4a10dbc98858481b5aedbcce3f3026dc271/tutorials" |
2 |
).then(async (response) => { |
3 |
postsData = await response.json(); |
4 |
postsData.map((post) => createPost(post)); |
5 |
filterData = [ |
6 |
...new Set( |
7 |
postsData
|
8 |
.map((post) => post.categories) |
9 |
.reduce((acc, curVal) => acc.concat(curVal), []) |
10 |
)
|
11 |
];
|
12 |
filterData.map((filter) => createFilter(filter)); |
13 |
});
|
5. Handle Filtering when Clicked
Now we’ve gotten our filter buttons and initial data, we can define a function to handle filtering the data when a button is clicked. This can be done using the .filter()
method on the posts data array.
This is the logic we’ll use for filtering the data:
- Create a function
handleFilterPosts()
that accepts a filter param - Use the
.filter()
method to filter our posts data based on the filter param - Clear all elements in posts-container and append the new filteredData to the container.
1 |
const handleFilterPosts = (param) => { |
2 |
let filteredPosts = [...postsData].filter(post => post.categories.includes(param)) |
3 |
|
4 |
postsContainer.innerHTML = ""; |
5 |
filteredPosts.map(post => createPost(post)) |
6 |
};
|
We want to detect when a button has been clicked and update the button state. In this tutorial, we’ll toggle the buttons so if clicked once, the button is set to active and if clicked again, the button is set to inactive.
1 |
const handleButtonClick = (e, param) => { |
2 |
const button = e.target; |
3 |
const buttonState = button.getAttribute('data-state'); |
4 |
|
5 |
if (buttonState =='inactive') { |
6 |
button.classList.add('is-active'); |
7 |
button.setAttribute('data-state', 'active'); |
8 |
} else { |
9 |
button.classList.remove('is-active'); |
10 |
button.setAttribute('data-state', 'inactive') |
11 |
}
|
12 |
}
|
We also want to make sure only one button is selected at a time and if no button is selected, the posts should display the default data so we can create functions to handle that logic:
1 |
const resetFilterButtons = (currentButton) => { |
2 |
const filterButtons = document.querySelectorAll('.filter-button'); |
3 |
[...filterButtons].map(button => { |
4 |
if (button != currentButton) { |
5 |
button.classList.remove('is-active'); |
6 |
button.setAttribute('data-state', 'inactive') |
7 |
}
|
8 |
})
|
9 |
}
|
10 |
|
11 |
const resetPosts = () => { |
12 |
postsContainer.innerHTML = ""; |
13 |
postsData.map((post) => createPost(post)); |
14 |
}
|
Finally, we can update our button click function:
1 |
const handleButtonClick = (e, param) => { |
2 |
const button = e.target; |
3 |
const buttonState = button.getAttribute('data-state'); |
4 |
resetFilterButtons(button); |
5 |
|
6 |
if (buttonState =='inactive') { |
7 |
button.classList.add('is-active'); |
8 |
button.setAttribute('data-state', 'active'); |
9 |
handleFilterPosts(param) |
10 |
} else { |
11 |
button.classList.remove('is-active'); |
12 |
button.setAttribute('data-state', 'inactive') |
13 |
resetPosts() |
14 |
}
|
15 |
}
|
Conclusion
And with that, we’ve completely built a filtering component for data on a webpage using vanilla JavaScript!
This content originally appeared on Envato Tuts+ Tutorials and was authored by Jemima Abu
Jemima Abu | Sciencx (2022-09-30T21:45:59+00:00) How to Filter Data on a Webpage (with JavaScript). Retrieved from https://www.scien.cx/2022/09/30/how-to-filter-data-on-a-webpage-with-javascript/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.