Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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().then(function(resp) {     return UserData.getUserPhotos(resp.UserId); }).then(function (resp) {     // do more stuff... });  

Now I have tried doing something similar in my component (replacing .then for .subscribe) however my error console going crazy!

@Component({     selector: 'profile',     template: require('app/components/profile/profile.html'),     providers: [],     directives: [],     pipes: [] }) export class Profile implements OnInit {      userPhotos: any;     userInfo: any;      // UserData is my service     constructor(private userData: UserData) {     }      ngOnInit() {          // I need to pass my own ID here...         this.userData.getUserPhotos('123456') // ToDo: Get this from parent or UserData Service             .subscribe(             (data) => {                 this.userPhotos = data;             }         ).getUserInfo().subscribe(             (data) => {                 this.userInfo = data;             });     }  } 

I'm obviously doing something wrong... how would I best with Observables and RxJS? Sorry if I am asking stupid questions... but thanks for the help in advance! I have also noticed the repeated code in my functions when declaring my http headers...

like image 494
Mike Sav Avatar asked Feb 08 '16 11:02

Mike Sav


People also ask

How to create a service with observable in angular?

With Observable we need a method in our code that will subscribe to this observable. Observable is used by Angular itself including angular event and angular HTTP client service that is why we’re covering observable here. Create a service using command: ng g s album. Here we’ll create a class AlbumService.

How to get all albums in angular using observable?

Observable is used by Angular itself including angular event and angular HTTP client service that is why we’re covering observable here. Create a service using command: ng g s album. Here we’ll create a class AlbumService. In AlbumService class create a method, say getAllAlbums (), which will make HTTP GET request using Observable.

How do I join two observables in RxJS?

In order to do that, we can use the forkJoin RxJS operator, which is similar to the old $q.all () from Angular 1 and lets you execute two or more Observables in parallel: As you can see from the example, forkJoin returns an Array with the results of the joined Observables.

What is the return type of observable in JavaScript?

The return type is Observable<SearchItem[]>, it’s going to return an observable where each item in the observable is SearchItem[], each item in the observable is going to be an array of SearchItems.


Video Answer


1 Answers

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 once 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 another one. Don't forget to import the operator to be able to use it:

import 'rxjs/add/operator/flatMap'; 

This answer could give you more details:

  • Angular HTTP GET with TypeScript error http.get(...).map is not a function in [null]

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 (you need to add import 'rxjs/add/observable/forkJoin'):

Observable.forkJoin([   this.userData.getUserPhotos(),   this.userData.getUserInfo()]).subscribe(t=> {     var firstResult = t[0];     var secondResult = t[1]; }); 
like image 162
Thierry Templier Avatar answered Oct 11 '22 10:10

Thierry Templier