July 10, 2020

Creating a real-time search functionality using RxJs

Guys today we are going to implement real-time search implementation using RxJS(Reactive extension of javascript)

Real-time search functionality in the sense for every user input search string we need to make API calls to the server to bring data.

Now, We need to consider some point while implementing search functionality

  • At least three characters to be entered for making search api call
  • When user stop typing then only search api call should go
  • Simultaneous api call should not go for api call
  • Api call should happen when search string is different from previous search string.

You want check code and demo then you can access using below links

let’s start implementing

We will implementing real-time search functionality with only javascript and rxjs library

Please subscribe for web development tutorials

Creating user interface

HTML file

<!DOCTYPE html>

<head>
    <link rel="stylesheet" href="index.css" </head>

<body>
    <section class="search-section">
        <label>Search posts</label>
        <input placeholder="Enter at least 3 character to search" id="searchEle" type='search'>
        <div >
            <ul id="result"></ul>
        </div>
    </section>

</body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.1.0/rxjs.umd.js"></script>
<script src="index.js"></script>

</html>

As you can see above we have created a simple HTML where we have added to the script tag

first one is a cdn for rxjs library which is used for accessing rxjs utilities

second one is index.js which we will use for writing real-time search implementation

CSS file

input {
    display: block;
    margin: 17px auto;
    width: 100%;
    height: 35px;
    border: none;
    outline: none;
    border-bottom: 3px solid blueviolet;
}
label {
    font-size: larger;
}
section {
    text-align: center;
    height: 500px;
    width: 500px;
    margin: 0 auto;
    /* font-size: larger; */
    font-family: sans-serif;
}
#result {
    text-align: left;
    list-style: none;
    padding: 0;
}
#result li {
    padding: 6px;
    border: 0.5px solid;
    box-shadow: 1px 1px 0.5px;
    margin: 10px;
}

Written a css file for designing a web page which will look like below

Writing a Business logic

const searchInput = document.getElementById('searchEle');
const searchInput$ = rxjs.fromEvent(searchInput, 'keyup');
const result = document.getElementById('result')

const {
    debounceTime,
    map,
    switchMap,
    distinctUntilChanged,
    filter,
    concatMap,
    toArray
} = rxjs.operators;
const { ajax } = rxjs.ajax;


searchInput$.
    pipe(
        map(input => input.target.value),
        filter(query => query.length > 2),
        distinctUntilChanged(),
        debounceTime(600),
        switchMap(query => getPosts(query)))
    .subscribe((searchResult) => {
        if (searchResult && searchResult.length) {
            result.innerHTML = searchResult.map(search => {
                return `<li>
                            <div>
                                <label>Name: </label>
                                <span>${search.name}</span>
                            </div>
                            <div>
                                <label>
                                    Url: 
                                </label>
                                    ${search.latest}
                                <span>
                                </span>
                            </div>
                            

                        </li>`
            }).join('');
        } else {
            result.innerHTML = '<strong>No data available</strong>'
        }

    })


getPosts = (searchString) => {
    return ajax.getJSON(`https://api.cdnjs.com/libraries?search=${searchString}`)
        .pipe(
            map(response => response.results.slice(0, 10))
        )
}

const searchInput = document.getElementById(‘searchEle’) – taken a snapshot of search input element where user enters intended search string

const searchInput$ = rxjs.fromEvent(searchInut, ‘keyup’) – created an observable for keyup event on searchInput. It means it emits stream of keyup events.

const result = document.getElementById(‘result’) – taken a snapshot of dom element which we will going to use for displaying result

we have use rxjs.operators which we need for implementing search functionality and stored in

debounceTime,
map,
switchMap,
distinctUntilChanged,
filter,
concatMap,
toArray

and also we need getJson method of ajax for making an api call

Now let’s understand the main functionality

searchInput$.
    pipe(
        map(input => input.target.value),
        filter(query => query.length > 2),
        distinctUntilChanged(),
        debounceTime(600),
        switchMap(query => getPosts(query)))
    .subscribe((searchResult) => {
        if (searchResult && searchResult.length) {
            result.innerHTML = searchResult.map(search => {
                return `<li>
                            <div>
                                <label>Name: </label>
                                <span>${search.name}</span>
                            </div>
                            <div>
                                <label>
                                    Url: 
                                </label>
                                    ${search.latest}
                                <span>
                                </span>
                            </div>
                            

                        </li>`
            }).join('');
        } else {
            result.innerHTML = '<strong>No data available</strong>'
        }

    })

Considering you guys have some knowledge on RxJs

as we know searchInput$ will emit a sequence of keyup events but before reaching to API we need to manipulate or change the output event.

like, we don’t need whole key up event object, we just need search string so we added map operator which will help to emit only search string

we used the filter operator method which helps to prevent event emitting until and unless search string is not greater than 2 character

distinctUntilChanded operator will help us to check that the previous inputted string is not the same as the current one

debounceTime operator help us to add a delay before making API call for avoiding subsequent API call

Now the final one switchMap operator – there are some more operators like mergeMap, concatMap, exhaustMap who behave like switchMap but have slightly different functionality and different use cases. If you want to know the difference between this all operator then go through this post

In our case switchMap fits because switchMap internally subscribe to source observable means searchInput$ and pass result to innerObservable

In our case, we are passing it to the getPost() method which calls the API method and returns the observable.

But the main advantage of switchMap is that for eg search API call in pending state and before that observable emits an event. so,current pending call will get cancel and the new call will make with the new search string. So API roundtrip will be reduced

Conclusion:

Rxjs is a very powerfull utility library based on observable and events. real time search is one of the example using rxjs. There are number of functionality you can achieve using rxjs

If you like post , follow me on twitter and share this article and let me know in comment If you have any doubt.

Please subscribe for web development tutorials

Leave a Reply

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