Angular with RxJS

The HttpModule is Angular’s built-in module for working with HTTP requests/responses. This needs to be imported in the module that will contain the service making the calls.

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';

import { AppComponent } from './app.component';
import { OrgChartComponent } from './org-chart/org-chart.component';
import { PositionComponent } from './position/position.component';
import { DataService } from './data.service';
import { SalaryService } from './salary.service';

@NgModule({
  declarations: [
    AppComponent,
    OrgChartComponent,
    PositionComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    HttpModule
  ],
  providers: [
    DataService,
    SalaryService
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

In the service class that will be making the HTTP calls, we need to inject the HttpService through the constructor.

 constructor(private http:Http) { }

Once the HTTP service is injected, we can now make the calls in the service. The HTTP service returns an Observable, so we need to make sure we are able to handle it. For each piece we plan to use, we import it from the RxJS. For the main Observable, we import like so.

import { Observable } from 'rxjs/Observable';

With the Observable, we can now implement the method that makes the HTTP call and returns Observable.

 getPost() : Observable { 
   let url = 'http://jsonplaceholder.typicode.com/posts'; 
   params.append('id', '1'); 
   return this.http.get(url).map(this.mapPost).catch(this.handleError); 
 }

Note that the example above is chaining multiple commands after the http.get call. For each of these chained calls, we need to make sure if have imported the appropriate RxJS service. Here is the complete example:

import { Injectable } from '@angular/core';
import { Http, Response, Headers, RequestOptions,
  URLSearchParams } from '@angular/http';

import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/delay';
import 'rxjs/add/observable/throw';
import 'rxjs/add/observable/of';
import 'rxjs/add/operator/finally';
import 'rxjs/add/operator/switchMap';
import { Post } from './post';

@Injectable()
export class DataService {

    constructor(private http:Http) { }

    handleError(res: Response | any) : Observable {
        let errorMessage = 'error';
        if (res instanceof Response) {
            const body = res.json() || '';
            const err = body.error || JSON.stringify(body);
            errorMessage = `
              ${res.status} -
              ${res.statusText} -
              ${err}
            `;
        }
        return Observable.throw(errorMessage);
    }

    createPost() : Observable {
        let url = 'http://jsonplaceholder.typicode.com/posts';
        let post = {
            userId: 1,
            title: 'My Title',
            body: 'the body'
        };
        let headers = new Headers({ 'Content-Type': 'application/json' });
        let params = new URLSearchParams();
        params.append('id', '1');
        let options = new RequestOptions({ headers, params });
        return this.http.post(url, post, options)
                        .map(this.mapPost)
                        .catch(this.handleError);
    }

    mapPost(res: Response) : Post {
        let post: Post = res.json();
        return post;
    }
    someFunction() {
      console.log('in someFunction');
    }
    getPostById(id: number) : Observable {
        let url = 'http://jsonplaceholder.typicode.com/posts/' + id;
        return this.http.get(url)
                        .map(this.mapPost)
                        .switchMap(() => Observable.of({ id: 77}))
                        .catch(this.handleError)
                        .delay(3000);
    }
}

Note that in the handleError method we are able to handle the HTTP response (which is a Response object) and work with the HTTP status and statusText.

To use the observable, we have to subscribe to it. This would be done in the component class that is calling the service.  In the component, make sure the service is injected through the constructor. By best practice we do service calls in the ngOnInit() lifecycle hook method.

export class MyComponent implements OnInit {
  constructor (private service: DataService) { };

  ngOnInit() {
   this.service.getPostById(1).subscribe(
     (data: Post) => console.log(data),
     (err) => console.log(JSON.stringify(err))
   );
  }}

The example above is expecting a “Post” object in the response. It is also passing a second parameter to the subscribe method, which is the call back function of onError.

Async Pipe

We can pipe the “async” keyword in the template so that it only executes that template code once the data response is received.

<h3 *ngIf="blogpost | async as post">
  {{ blogpost }} 
</h3>

The example above the <h3> element will only be displayed once the post variable has been resolved from the HTTP response.

 

Note that for Posts and Puts, we should have HTTP headers and options. This can be seen in the example above.