Mike Sav February 2016

Chaining RxJS Observables from http data in Angular2 with TypeScript

I'm currently trying to teach myself Angular2 and TypeScript after happily working with AngularJS 1.* for the last 4 years! I have to admit I am hating it but I am sure my eureka moment is just around the corner... anyway, I have written a service in my dummy app that will fetch http data from a phoney backend I wrote that serves JSON.

import {Injectable} from 'angular2/core';
import {Http, Headers, Response} from 'angular2/http';
import {Observable} from 'rxjs';

@Injectable()
export class UserData {

    constructor(public http: Http) {
    }

    getUserStatus(): any {
        var headers = new Headers();
        headers.append('Content-Type', 'application/json');
        return this.http.get('/restservice/userstatus', {headers: headers})
            .map((data: any) => data.json())
            .catch(this.handleError);
    }

    getUserInfo(): any {
        var headers = new Headers();
        headers.append('Content-Type', 'application/json');
        return this.http.get('/restservice/profile/info', {headers: headers})
            .map((data: any) => data.json())
            .catch(this.handleError);
    }

    getUserPhotos(myId): any {
        var headers = new Headers();
        headers.append('Content-Type', 'application/json');
        return this.http.get(`restservice/profile/pictures/overview/${ myId }`, {headers: headers})
            .map((data: any) => data.json())
            .catch(this.handleError);
    }

    private handleError(error: Response) {
        // just logging to the console for now...
        console.error(error);
        return Observable.throw(error.json().error || 'Server error');
    }   
}

Now in a Component I wish to run (or chain) both getUserInfo() and getUserPhotos(myId) methods. In AngularJS this was easy as in my controller I would do something like this to avoid the "Pyramid of doom"...

// Good old AngularJS 1.*
UserData.getUserInfo().        

Answers


Thierry Templier February 2016

For your use case, I think that the flatMap operator is what you need:

this.userData.getUserPhotos('123456').flatMap(data => {
  this.userPhotos = data;
  return this.userData.getUserInfo();
}).subscribe(data => {
  this.userInfo = data;
});

This way, you will execute the second request when the first one is received. The flatMap operator is particularly useful when you want to use the result of the previous request (previous event) to execute antoher one. Don't forget to import the operator to be able to use it:

import 'rxjs/add/operator/mergeMap';

This answer could give you more details:

If you want to only use subscribe method, you use something like that:

this.userData.getUserPhotos('123456')
    .subscribe(
      (data) => {
        this.userPhotos = data;

        this.userData.getUserInfo().subscribe(
          (data) => {
            this.userInfo = data;
          });
      });

To finish, if you would want to execute both requests in parallel and be notified when all results are then, you should consider to use Observable.forkJoin:

Observable.forkJoin([
  this.userData.getUserPhotos(),
  this.userData.getUserInfo()]).subscribe(t=> {
    var firstResult = t[0];
    var secondResult = t[1];
});

Post Status

Asked in February 2016
Viewed 1,336 times
Voted 5
Answered 1 times

Search




Leave an answer