Typeaheads – Avoid Frequent Backend calls with RxJS debounce……

If you are implementing any typeaheads like when as user types in and you display the result immediately, obviously for displaying these results you are back end API calls from your front end angular app. Now there is one gotcha over typically the way you do it on key for some number of characters (for.e.g 3 characters) you start making back end api calls for each key press, which poses challenge in itself. So what if if we have an way we make an API call when user user stops typing in or with some time delays. This is where RxJS debounceTime comes to rescue.

As explained earlier  RxJS allows you to work with asynchronous data streams. Now once a value is emitted from stream, debounce will pause its emission for specific X amount of time to see if another value is emitted, it is blocking the stream during this time. If a new value is emitted during the debounce time then the timer is restarted and debounce waits again for the full time. If its timer expires without any new value being emitted, it let the latest value pass. This can be very helpful in the scenarios of type-ahead.

Here is the sample screen shot.

Debounce sample

So as I type in I making calls to to Git Hub User API and displaying the HTML URL. So over here I have stopped thrice so three results.

Here is the code snippet for component and Html Template

import { Component, ViewChild, ElementRef, AfterViewInit } from '@angular/core';
import { Http, Response } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/fromEvent';
import 'rxjs/add/operator/debounceTime';
import 'rxjs/add/operator/pluck';
import 'rxjs/add/operator/filter';
import 'rxjs/add/operator/map';
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements AfterViewInit  {
  gitUsers: string[];
  title = 'app works!';
  @ViewChild('searchInput') searchInput: ElementRef;

  constructor (private http: Http) {
    this.gitUsers = new Array<string>();
  }

  ngAfterViewInit(){
    console.log(this.searchInput.nativeElement.value);
    Observable.fromEvent(this.searchInput.nativeElement, 'keyup')
      .debounceTime(500)
      .pluck('target', 'value')
      .filter((value: string) => value.trim().length > 0)
      .map((values: string) => {
        return this.gitUsersSearch(values)
      })
      .forEach(data => {
          data.subscribe(
            (result: Response) => {
              console.log(result);
              let responseBody = result.json();    
              this.gitUsers.push(responseBody.html_url);
              console.log(this.gitUsers);
            }
          );
      });
  }
  gitUsersSearch(searchTerm: string){
    console.log("Inside gitUsersSearch");      
    return this.http.get("https://api.github.com/users/" + searchTerm);
  }
}

Html Template

Debounce sample2

So apart from debounceTime I have used following additional API’s from Observables

  • Pluck –  It returns an Observable containing the value of a specified nested property from all elements in the Observable sequence. If a property can’t be resolved, it will return undefined for that value.
  • filter –Filter operator filters an Observable by only allowing items through that pass a test that you specify in the form of a predicate function.
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s