Prerequisites
HTMLJavaScriptSheetsBlocks
Intro
This advanced demo will show you how to set up a filter and search system that will work within a page on your website. Note, this is not a full site search as it does not match results on other pages. It only scans the current page and filters out entries like blog posts, products, property listings, based on user input.
If you are looking for a site-wide search, try out our Search.io Integration Doc.
Implementation
The HTML
For this implementation to work, you'll need to structure Elements in a certain way and add specific classes so that the JavaScript can function in the right way.
There are three main elements we need:
- Filter buttons
- a reset filter button
- category filter buttons
- a search input
- the blocks (also referred to as entries in this article) to show/hide based on the user input
The following will show the set up for each of these elements.
1. Filter Buttons
Since there will most likely be a few filter options, we can make a block for these.
Category List Item Block
The reset all and category filter buttons will use this Block. It is a simple block with only one List Item element within it.
This block has
- A single List Item Element
- Three variables for class, id, and text (see below)
- The Class variable is attached to the List Item's class attribute
- The ID variable is attached to the List Item's id attribute (only the reset all filter button will use this, so leave the default value empty)
- The Text attribute is attached to the List Item's text attribute
- Custom styling
This Block's variables are as follows:
Reset Filter Button
The reset filter button will be the first item in our list of categories. To set this up, here is the structure for out category list. Note that the List Item Block is being nested in an Unordered List element. We are also using a Sheetfeed element to pull the text information for the category buttons from a Sheet.
Taking a closer look at that first list item, we need to give set its variables.
- Class - set to "active-filter"
- ID - set to "reset-categories"
- Text - "All"
Category Buttons
In this demo, we are using a Sheet to store the text information for the rest of the categories. We can iterated over the rows in the sheet to create a cleaner, more manageable system. The Sheet is called "Property Categories Info" and contains one column (column A) where each row has a text value.
To get these to render, we are using a Sheetfeed element referencing this sheet and have nested the List Item Block inside the Sheetfeed. Then, to set up the variables, we set
- Class - set to "filter"
- ID - leave blank
- Text - set to "=A"
This renders a List Item Block for each row in our Sheet. Each List Item will function as a category filter button.
2. Search Input
The search input is a single Input element with some styling. Set its attributes as follows
- Type - set to "text"
- Placeholder - set to "Search this page" or whatever you want the text to be when there is no user input text
- Disabled, Autocomplete, Required, autoFocus, Kwes Multistep, Kwes data-kw-group - set to "False"
- ID - set to "property-search"
3. Blocks to Show/Hide
For this section, we will need two types a Div containers.
- The overall Div containing all the entries, used to style the layout
- A Card Wrapper Div that wraps each individual entry
Containing Div
Give this Div a Id of "directory-inner" and style it how you like, either using display flex or grid to set up the layout for your entries.
Card Wrapper Divs
Inside this div where you cna structure and style your entries to customize them to be product listings, property postings, blog posts, etc. In this demo, we are using a Blcok called "Card Wrapper Block" to hold the information about real estate properties. We also are using a Sheetfeed to render a Card Wrapper Block for each row with the appropriate information.
Here is the general structure of this Block. Note that all the context actually goes within a nested Div labeled "Card Container." The contents of this Div are custom.
You need to give the Card Wrapper Block a class attribute of "property-post property-post-active" which is actually two classes separated by a space. If this Div has the "property-post-active" class, it will be shown on the page, otherwise it will be hidden.
The JavaScript we need will effectively toggle this class on each of the entries depending on which filters are selected. That is the next thing to implement.
The JavaScript
In order to implement this filter and search functionality, you will need to include this script. Copy and paste this text into a Script element's text property. This script element should be the last element or close to the last element in the element's column.
window.addEventListener("DOMContentLoaded", () => {
let search = document.getElementById("property-search");
let entries = document.getElementById('directory-inner').getElementsByClassName('property-post');
let searchText = "";
let filter;
var filterButtons = document.querySelectorAll(".filter");
let allFilter = document.getElementById("reset-categories");
// Handles reset filter button
allFilter.addEventListener("click", () => {
for (i = 0; i < filterButtons.length; i++) {
filterButtons[i].classList.remove("active-filter");
for (var j = 0; j < entries.length; j++) {
entries[j].classList.add("property-post-active");
}
}
allFilter.classList.add("active-filter");
});
// Handles filter buttons
for (i = 0; i < filterButtons.length; i++) {
filterButtons[i].onclick = function () {
allFilter.classList.remove("active-filter");
filterButtons.forEach(function (btn) {
btn.classList.remove("active-filter");
});
filter = this.innerHTML;
filter = filter.replace(/\s+/g, "").toLowerCase();
this.classList.add("active-filter");
let entries = document.getElementById('directory-inner').getElementsByClassName('property-post');
for (var j = 0; j < entries.length; j++) {
entries[j].classList.remove("property-post-active");
if (
entries[j].innerHTML.replace(/\s+/g, "").toLowerCase().includes(filter) && entries[j].innerHTML.replace(/\s+/g, "").toLowerCase().includes(searchText)
) {
entries[j].classList.add("property-post-active");
}
}
};
}
// Handles text search input
search.addEventListener("keydown", (e)=> {
searchText = e.target.value.replace(/\s+/g, "").toLowerCase();
for (var j = 0; j < entries.length; j++) {
entries[j].classList.remove("property-post-active");
if (filter) {
if (entries[j].innerHTML.replace(/\s+/g, "").toLowerCase().includes(filter) &&
entries[j].innerHTML.replace(/\s+/g, "").toLowerCase().includes(searchText)
) {
entries[j].classList.add("property-post-active");
}
}
else if (entries[j].innerHTML.replace(/\s+/g, "").toLowerCase().includes(searchText)
) {
entries[j].classList.add("property-post-active");
}
}
});
});
If you aren't familiar with JavaScript, this code basically hides and shows non-matching blocks (sections of HTML) depending on which filter buttons are selected and the text in the search input.
Comments
0 comments
Please sign in to leave a comment.