Live Filter With JavaScript!

Live Filter With JavaScript!

Recently, I was building a side project web application on Covid-19 with Angular and I had to implement a filter feature. It was so cool that I decided to do the same in Vanilla JavaScript. So here it goes...

Let's get started, we will be using only three files for this code. First with the index.html file, we will create a minimal display of the search input field, and a list of countries.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Live Filter</title>
  <link rel="stylesheet" href="./style.css">
</head>
<body>
  <header>
    <h3>Live Filter</h3>
    <div class="form">
      <input type="text" name="filter" id="filter" placeholder="Search Countries">
    </div>
  </header>

  <div class="display">
    <h4>Countries</h4>
    <ul></ul>
  </div>

  <script src="./app.js"></script>
</body>
</html>

The main highlights of the html above are the 'input' tag where we will input our search query and the 'ul' tag where our list of countries will be displayed. I am not talking CSS here but to make the page not look entirely ugly, I will just add a CSS style.css file that contains the following:

@import url('https://fonts.googleapis.com/css2?family=Ubuntu&display=swap');

* {
  margin: 0;
  padding: 0;
}

body {
  color: purple;
  text-align: center;
  box-sizing: border-box;
  width: 100vw;
  overflow: hidden;
  font-family: 'Ubuntu', sans-serif;
}

header {
  background-color: purple;
  color: white;
  padding: 0.5rem 1rem;
  display: flex;
}

header h3 {
  padding: 3px;
  font-size: large;
  text-transform: uppercase;
  letter-spacing: 3.5px;
}

input {
  padding: 10px 5px;
  border:  none;
  border-radius: 4px;
  width: 70%;
}

::placeholder {
  font-size: 18px;
}

.form {
  flex: auto;
}

.display {
  width: 80vw;
  margin: 1.5rem auto;
  padding: 1rem;
  border: 2px dashed black;
  border-radius: 5px;
  font-size: 20px;
}

.display h4 {
  text-transform: uppercase;
  font-size: 1.5rem;
  padding: 0.5rem;
  letter-spacing: 3px;
  background-color: purple;
  color: white;
}

ul {
  list-style: none;
  text-align: start;  
}

li {
  padding: 0.3rem 2rem 0 0;
}

Now to the main part, the JavaScript. I will explain step by step showing the code for each step then give the final JavaScript code at the end. Ok, lets go!!

We will be declaring an array of countries which we will be use as our data for the DOM, your data could range from hard-coded data to fetching data from an API. Also we will be acessing the input and ul elements in tht HTML page.

const listData = [
  'Ghana', 'Togo', 'Nigeria', 'USA', 'Canada','Bahamas', 'Italy', 'France',
  'Isreal', 'Egypt', 'Iraq', 'Qatar', 'England', 'Ireland', 'Brazil', 'Chile'
];
let shownList= [];
const ul = document.querySelector('ul');
const searchCountry = document.querySelector('input');

The empty shownList is the array which retrieve the data when the DOM is painted/loaded for the first time as in the code below:

const PaintDOM = (arrArgument) => {
  let output ='';
  arrArguement.forEach((country) => {
    output += `<li>${country}</li>`;
  })
  ul.innerHTML = output;
}

const getInitialList = () => {
  shownList = listData;
  PaintDOM(shownList);
}

document.addEventListener('DOMContentLoaded', getInitialList);

The PaintDom function is a function which recieves an Array, takes each element in the array and pass it to a 'li' tag. For Example, it takes Nigeria and makes it <li>Nigeria<li>. ForEach() is the array function which helps us use each individual element in the array as we like to, there are others we will be using. If you are not very familiar with the ES6 arrray and objects methods, you will want to check them out, they are very useful. Moving on...

The PaintDom function then fixes each 'li' tags which now contains a country into the 'ul' HTML like this:

<ul>
  <li>Nigeria</li>
  <li>Chile</li>
  <li>England</li>
  <li>Iraq</li>
</ul>

Then when the DOM is loaded for the first time, the getInitialList function is loaded. The function assigns the data in listData to shownList and passes it as an argument into the PaintDOM function. On Loading the page we have

blog1.PNG

We will now implement our filter feature. We will be using two array methods, filter and includes. Here is the code:

searchCountry.addEventListener('input', (e) => {
  const search = e.target.value.toLowerCase();

  const FilteredList = shownList.filter((country) => {
    return country.toLowerCase().includes(search);
  });
  PaintDOM(FilteredList);
  // console.log(FilteredList);
});

The searchCountry is the variable we assigned to the input HTML element in the DOM, we are also adding an event listener so that whenever we type anything in the input tag, the arrow function in its code is fired up.

When a user types any letter in the input DOM section, the filter method searches for any country in the list data which contains the letter the user typed (this is what the includes array method does), whichever country passes this test is returned as anelement into the array FilteredList. The FilteredList is then passed into the earlier declared PaintDOM function which then modifies the list shown in the DOM.

Note that both the search query and the countries have been modified to all contain lowercase for easy comparisons.

Here is the JavaScript Code in full

const listData = [
  'Ghana', 'Togo', 'Nigeria', 'USA', 'Canada','Bahamas', 'Italy', 'France',
  'Isreal', 'Egypt', 'Iraq', 'Qatar', 'England', 'Ireland', 'Brazil', 'Chile'
];
let shownList= [];
const ul = document.querySelector('ul');
const searchCountry = document.querySelector('input');

const getInitialList = () => {
  shownList = listData;
  PaintDOM(shownList);
}

const PaintDOM = (arrArguement) => {
  let output ='';
  arrArguement.forEach((country) => {
    output += `<li>${country}</li>`;
  })
  ul.innerHTML = output;
}

document.addEventListener('DOMContentLoaded', getInitialList);

searchCountry.addEventListener('input', (e) => {
  const search = e.target.value.toLowerCase();

  const FilteredList = shownList.filter((country) => {
    return country.toLowerCase().includes(search);
  });
  PaintDOM(FilteredList);
  // console.log(FilteredList);
});

Thanks for reading.