Introduction
We have all seen a lot of websites which have real-time search filtering. This looks really good and provides a convenient user experience. If you are still wondering what real-time search is, it is a way of displaying the filtered result as the user is typing. This is much better than waiting for the user to finish typing the whole search query and then press a button. Real-time search saves time because the user need not type the whole query as there is a high chance that he/she will see the intended result before completing the query.
The concept behind filtering
The concept is quite simple. To conduct a search filter, we need something to search from. A list of sorts which has a collection of strings from which the user will search. It’s quite understood that we need to use an array for this in JavaScript.
So, now we have an array of strings to search from. Now, we need to make a function that can fetch all the relevant strings from the array based on the user’s search query. And this function needs to be called for every letter the user types. Based on the result of this function, we need to change the view and display the result on the screen. That’s it. That is the concept behind real-time search.
Now let’s get coding
- Let’s make a simple HTML page with a search box and an unordered list with a few dummy items. Create a new directory and in that create an “index.html” file. In that file, put some basic HTML code with an ‘input’ tag and an ‘ol’ tag with a few dummy ‘li’ tags in
<html> <head> <title>Realtime search demo</title> </head> <body> <input type="search" placeholder="search..." /> <ul id="result-list"> <li>sample result</li> <li>sample result</li> <li>sample result</li> </ul> </body> </html>
- In this step, let’s create the array we were talking about. In the same directory create a file called “main.js”. In that file copy-paste the below array.
let arr = ["anagrams-of-string-(with-duplicates)", "array-concatenation", "array-difference", "array-includes", "array-intersection", "array-remove", "array-sample", "array-union", "array-without", "array-zip", "average-of-array-of-numbers", "bottom-visible", "capitalize-first-letter-of-every-word", "capitalize-first-letter", "chain-asynchronous-functions", "check-for-palindrome", "chunk-array", "collatz-algorithm", "compact", "count-occurrences-of-a-value-in-array", "current-URL", "curry", "deep-flatten-array", "distance-between-two-points", "divisible-by-number", "drop-elements-in-array", "element-is-visible-in-viewport", "escape-regular-expression", "even-or-odd-number", "factorial", "fibonacci-array-generator", "fill-array", "filter-out-non-unique-values-in-an-array", "flatten-array-up-to-depth", "flatten-array", "get-days-difference-between-dates", "get-max-value-from-array", "get-min-value-from-array", "get-native-type-of-value", "get-scroll-position", "greatest-common-divisor-(GCD)", "group-by", "hamming-distance", "head-of-list", "hexcode-to-RGB", "initial-of-list", "initialize-array-with-range", "initialize-array-with-values", "is-array", "is-boolean", "is-function", "is-number", "is-string", "is-symbol", "last-of-list", "measure-time-taken-by-function", "median-of-array-of-numbers", "nth-element-of-array", "number-to-array-of-digits", "object-from-key-value-pairs", "object-to-key-value-pairs", "ordinal-suffix-of-number", "percentile", "pick", "pipe", "powerset", "promisify", "random-integer-in-range", "random-number-in-range", "redirect-to-URL", "reverse-a-string", "RGB-to-hexadecimal", "round-number-to-n-digits", "run-promises-in-series", "scroll-to-top", "shallow-clone-object", "shuffle-array", "similarity-between-arrays", "sleep", "sort-characters-in-string-(alphabetical)", "speech-synthesis-(experimental)", "standard-deviation", "sum-of-array-of-numbers", "swap-values-of-two-variables", "tail-of-list", "take-right", "take", "truncate-a-string", "unique-values-of-array", "URL-parameters", "UUID-generator", "validate-email", "validate-number", "value-or-default", "write-json-to-file"]
- Now, it’s time for the most important part of the code. The function to filter the array. Let’s break down the required function into small pieces.
- Let’s call the function “updateResult”.
- All functions generally have an input and an output. In this function, the input will be the what the user types in the search box. This will be the only argument the function takes. It won’t have any output but it will have an action i.e changing the view. So, it need not return anything.
function updateResult(query) { }
- Now, we need to call this function every time the user types something. The easiest way to do this is the “oninput” attribute of the “input” element. So, put an oninput attribute to our input box and pass its value.
<input oninput="updateResult(this.value)" type="search" placeholder="Search..." />
- Iterate through the array to linearly check each element if the entered words match the array elements. To check if it matches, you can use the Array.indexOf() function. If it returns -1 it doesn’t match. We need to call the indexOf() function f or each of the words the user enters. We can do that by using the split() and map() functions. Don’t forget to use String.toLowerCase() to ignore case sensitivity.
function updateResult(query) { arr.map(function(algo){ query.split(" ").map(function (word){ if(algo.toLowerCase().indexOf(word.toLowerCase()) != -1){ } }) }) }
- Everytime the ‘if’ condition passes, we need to add the ‘algo’ to the result list in the html page. For this, we can create a DOM object of the list and update its ‘innerHTML’.
function updateResult(query) { let resultList = document.querySelector(".result"); arr.map(function(algo){ query.split(" ").map(function (word){ if(algo.toLowerCase().indexOf(word.toLowerCase()) != -1){ resultList.innerHTML += `<li class="list-group-item">${algo}</li>`; } }) }) }
- This will keep adding items to the list as the function is called. The items will keep stacking up. To avoid this, we need to truncate the list at beginningning of the function itself. So, finally your code should look like this.
function updateResult(query) { let resultList = document.querySelector(".result"); resultList.innerHTML = ""; arr.map(function(algo){ query.split(" ").map(function (word){ if(algo.toLowerCase().indexOf(word.toLowerCase()) != -1){ resultList.innerHTML += `<li class="list-group-item">${algo}</li>`; } }) }) }
- Include the ‘main.js’ file in index.html
- Open the index.html file in your browser. It will look something like this.
Final thoughts
Wasn’t that easy?
I hope you understood how it works now. In this tutorial, we used simple linear search. This won’t always be feasible. When there are more elements in the array, better search algorithms need to be used. If you know of any good algorithms, please share in the comments below. Also, I will be hosting the code I wrote on GitHub. Feel free to make contributions.
You can see the live demo here.
- Test driven development with golang - July 31, 2018
- Speech recognition and synthesis with simple JavaScript - May 20, 2018
- How to scrape hashtags from Instagram using nodeJS - April 10, 2018
Hi
Thats a very neat code, but I found this little bug.
When u set “con con con con” as the query filter, the item “array-concatenation” is being added like 4 times to the final result. before an item being added we should check whether algo we’re working on is not in the results already to avoid creating redundant result.
Hi,
Nice catch!! This is a simple boilerplate code for the filter just to explain how it works. There could be a lot of bugs. They can be squashed based on the use case. But again, nice catch!
Hi Arjun Mahishi,
Thanks for the tutorial, there is a little observation I want to make in this declaration: let resultList = document.querySelector(“.result”);
I believe you meant: let resultList = document.querySelector(“#result-list”);
A beginner might have trouble spotting this.
Yes!! Thanks for pointing it out. I don’t know how I missed it. I’ll change it.
How would the code be adjusted to make this work but with images? And have all images hidden before searching? If possible of course!
This to enought to filter . fix bug duplicate source
function updateResult(query) {
let resultList = document.querySelector(“.result”);
resultList.innerHTML = “”;
arr.map(function(algo){
if(algo.toLowerCase().indexOf(query.toLowerCase()) != -1){
resultList.innerHTML += `<li class="list-group-item">${algo}</li>`;
})
})
}
Thank you, this is a lifesaver…
Hi, how would you trigger an action (say set the resultList.innerHTML to “Couldn’t find anything”) if there were no results found in the array?
Thanks
Hi, how would one make the result list show a message (e.g. “no results found”) if there are no results in the array that match the query?
Hi, is there a way to
Thanks btw, this is something i really needed.
can u just give me the whole html s i can coppie and past it
check the html code is messing class result, or either alter the js code to set and attribute to the element , i have instead inspected the code demo page to find out what is wrong with the example and found that.