Real-time search using basic JavaScript

real-time search using basic javascript

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

  1. 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 it
    <!DOCTYPE html>
    <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>
    

    Simple HTML code

  2. 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"]
    
    



  3. 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 for 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 the begining 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>`;
      			}
      		})
      	})
      }
      
  4. Include the ‘main.js’ file in index.html
  5. Open the index.html file in your browser. It will look something like this.
    Simple demo

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.

Author: Arjun Mahishi

Human by birth, machine by behaviour, geek by choice.

2 Thoughts

  1. 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.

  2. 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!

Leave a Reply

Your email address will not be published. Required fields are marked *