Wednesday, June 29, 2016

Typeahead search with Angular2 and TypeScript


This blog describes typeahead search implementation using Angular 2 and TypeScript. The functionality allows user to start typing in a form field and provides list of recommendations with the given text. See my previous blogs for Angular 1.x implementation and Introduction to RxJS in Angular 2



Type ahead search: 

Off late, one of the common feature in forms (on a web page) is type ahead search. It is generally tied to text fields and drop-downs. The functionality allows user to start typing in a form field and it provides list of recommendations with the given text.

The implementation is relatively simple for fields like country list or states list. We can download the complete list in the browser and filter through while user is typing. However, if it is a stock ticker, we might need to retrieve data dynamically from a server API. Here, efficiently managing the server calls is critical.


Reactive Extensions - JavaScript : 

RxJS (Reactive Extensions JavaScript) and observables are quite effective with requirements like typeahead search.

RxJS is nothing but,
  1. Observables -  asynchronously process stream of data. The source of the stream could be network resources (Server APIs) or UI controls. Observable emits items in a stream and an observer processes them.
  2. Operators - that act on emitted sequence of items. Examples: 
      1. map() for transforming results
      2. take(n) for selecting first n items from an observable
  3. Scheduler - for scheduling and decision making on when to emit an item in an observable.

My previous two blogs(1 & 2) discussed RxJS and Observables. Type ahead search is even a better example for the following reasons and complexity
  • A continuous stream of events are emitted from the UI - user types characters in the text field resulting in new information each key press.
  • Potentially each key press can result in server side API call to retrieve new information. Handle results from the API calls asynchronously. 


Implementation: 

Consider following component code,

 @Component({
    selector: 'typeahead-search',
    templateUrl: 'app/templates/search.tpl.html'
 })
 export class AppComponent
 {
    searchForm: any;
    results: Observable<any>;  
 
    constructor(private fb: FormBuilder, private http: Http){
        this.searchForm = this.fb.group({
            'searchField': [''] // we can set default value - it is set to be an empty string here.
        });

        // reference the control (ngControl)
        var ctrl = this.searchForm.controls.searchField;



        this.results = ctrl.valueChanges
                    .switchMap(fieldValue => this.http.get(`http://localhost:3001/api/search?term=${fieldValue}`))
                    .map(res => res.json());

 }


We are creating an element/component named typeahead-search. We have a single text field in the form. Form Builder API helps create Control Group, set up validations etc. For simplicity, we are not adding any validations for the typeahead text field in the sample.

Consider following line of code. This line is at the heart of type ahead search. That's all it takes to implement typeahead search in Angular 2. 

        
this.results = ctrl.valueChanges
                    .switchMap(fieldValue =>          this.http.get(`http://localhost:3001/api/search?term=${fieldValue}`))
                    .map(res => res.json());

  • On the control (text field) valueChanges is an observable<any>. It emits new text as user is typing. It emits new text.
  • On the observable, the switchMap() operator accepts each value emitted and passes it on to the callback. The emitted values are latest search string on the control. The callback function makes an HTTP call using http.get API. 
  • The returned object is transformed to desired result using another RxJS operator map

Debounce: debounceTime(timeInMilliseconds)

It is another useful RxJS operator. It restricts emitting items from an observable only after the given timespan. It drops events till the given time and emits the latest. For example, if we use it on valueChanges observable in the above example, next value is emitted only after given milliseconds. Only the latest is emitted. That is, as user is typing text, if we set debounce to 500 milliseconds, newer text is returned (emitted) at 500 milliseconds interval (while user is typing). This reduces number of API calls to the server and makes the whole thing manageable. Consider following code and images


        this.results = ctrl.valueChanges

                    .debounceTime(500)
                    .switchMap(fieldValue => this.http.get(`http://localhost:3001/api/search?term=${fieldValue}`))
                    .map(res => res.json());




Code Sample

For the complete code sample, follow the link

References

Sunday, June 26, 2016

Implementing HTTP Client in Angular 2 using Observables (RxJS) and Promises


Angular 2 provides a choice between Observables and Promises for developing a HTTP client that invokes server side API. This blog discusses the two options.


RxJS Introduction - Reactive Extensions (Rx) is a Microsoft backed open source project. It is an event driven, asynchronous design approach. It helps develop effectively for a stream of data returned through asynchronous and time consuming operations. The async operation could be network operations, UI interactions, file IO etc. There are Rx libraries available for galore of programming languages like C#, Python, JavaScript, Java so on. Follow this link for a complete list. As you might have guessed, RxJS is JavaScript library for Reactive Extensions.

Angular 2, RxJS and Promises- At first, let us look at Angular 2's usage of RxJS for making HTTP calls. Later in the blog, we will review promises.

HTTP calls are asynchronous in JavaScript. Earlier implementations of Angular (1.x) used promises. It has success and error callbacks that are invoked when the call is done.

Angular 2 provides a choice between RxJS and Promises. Observables support stream of data, where as promises are done once the current invocation is complete. And also, observables could be cancelled (or unsubscribed).

While RxJS 4 focussed on ES 5 implementation, RxJS 5 is a rewrite for ES 2015 (ES 6). For more details on RxJS 5, follow this link to GitHub Repo. It is in beta at the time of writing this blog.

Note: My previous blog discusses RxJS 4 in an Angular 1.x application. Follow the link to check-out the blog.

A Sample implementation - Just so that focus is on demonstrating HTTP client, will take a very simplistic code sample. It shows list of players (sports stars) on a page. The list is obtained from a node service (server side) over a HTTP GET call, on click of a button. Consider following image.


We will be implementing this using Angular 2 and TypeScript.

The code to retrieve players is encapsulated in playerService.ts Consider following code. Read through the comments for details on each line of code.

// Injectable decorator for allowing a class to be exported as service/provider.
import {Injectable} from '@angular/core';

// Http and Response for making HTTP calls
import {Http, Response} from '@angular/http';


// RxJS Observable

import {Observable} from 'rxjs/Observable'

// Get everything rxjs
import 'rxjs/Rx';

// Injectable decorator for allowing a class to be exported as service/provider.
@Injectable()
export class PlayerService {
   

    // inject Http instance for making HTTP calls.
    constructor(private http: Http){}


    getData(): Observable<Response> {
        return this.http.get('api/search');
    }
}


Consider the getData() function, it returns an observable of HTTP response. 

What is an obserable? It is an array or stream of data made available asynchronously. As the term indicates it is an object that could be observed for data to be made available. The observable emits data only when there is an observer. In other words, the observable could be subscribed to by an observer.

Consider following code. It is a function in an Angular 2 component. This component is bound to a UI template. The component subscribes to the observer on click of the button with caption "Get player list".

  getData(){
    this.serviceInstance
      .map(result => result.json())
      .subscribe( result => this.players = result);
  }


Following the link for the complete component class.

map is an RxJS operator for transforming the response to player list. The players array on the component is bound to the associated view/template. Refer to the following template code. ngFor iterates through players array. Bindings on JSON properties can be seen with-in the curly braces - {{}}.

    <div *ngFor="let item of players">
        <div>
            <strong>{{item.name}}</strong>
            <div><span>{{item.age}}</span> . <span>{{item.gender}}</span></div>
            <div>{{item.email}}</div>
            <div><hr></div>
        </div>
    </div>


Promises - Above functionality could be achieved using familiar promises as well. Observables are advisable for their sophistication. But if you prefer to stick to promises, API is available.

Promise too is asynchronous. After making a HTTP call. success or error callback are invoked with the response. Consider following code snippet in the service class (playerService.ts). It returns promise of HTTP response.

    getDataAsAPromise(): Promise<Response> {
        return this.http.get('api/search').toPromise(); // toPromise() is responsible for obtaining a promise from the get call.
    }


Consider following code. In the calling function, as the promise is resolved, one of the "then function callbacks" are invoked. First parameter is a success callback. Second parameter is an error callback. The success callback sets result on component's players array, which has bindings in the template. (refer to the template/HTML code in above section)

  getDataAsAPromise(){
    this.service.getDataAsAPromise().then( result => this.players = result.json(), error => console.log(error));
  }


Follow this link for complete code sample. "Read me" file has details to run the sample.


References

https://github.com/ReactiveX/rxjs
https://angular.io/docs/ts/latest/guide/server-communication.html#!#http-client
http://reactivex.io/languages.html
https://msdn.microsoft.com/en-in/data/gg577609.aspx