Encadenando RxJS Observables desde datos http en Angular2 con TypeScript

Actualmente estoy tratando de enseñarme a mí mismo Angular2 y TypeScript después de trabajar felizmente con AngularJS 1. * durante los últimos 4 años. Tengo que admitir que lo odio, pero estoy seguro de que mi momento eureka está a la vuelta de la esquina … de todos modos, he escrito un servicio en mi aplicación ficticia que buscará datos http de un backend falso que escribí para 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'); } } 

Ahora en un componente deseo ejecutar (o encadenar) los getUserInfo() y getUserPhotos(myId) . En AngularJS esto fue fácil ya que en mi controlador haría algo como esto para evitar la “pirámide del destino” …

 // Good old AngularJS 1.* UserData.getUserInfo().then(function(resp) { return UserData.getUserPhotos(resp.UserId); }).then(function (resp) { // do more stuff... }); 

Ahora he intentado hacer algo similar en mi componente (sustituyendo .then por .subscribe ), ¡pero mi consola de error se está volviendo loca!

 @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; }); } } 

Obviamente estoy haciendo algo mal … ¿cómo podría hacerlo mejor con Observables y RxJS? Lo siento si estoy haciendo preguntas estúpidas … ¡pero gracias por la ayuda con anticipación! También he notado el código repetido en mis funciones al declarar mis encabezados http …

Para su caso de uso, creo que el operador de flatMap es lo que necesita:

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

De esta manera, ejecutará la segunda solicitud una vez que se reciba la primera. El operador flatMap es particularmente útil cuando desea utilizar el resultado de la solicitud anterior (evento anterior) para ejecutar otro. No olvide importar el operador para poder usarlo:

 import 'rxjs/add/operator/flatMap'; 

Esta respuesta podría darle más detalles:

  • HTTP angular GET con error de tipografía http.get (…). Map no es una función en [nulo]

Si solo quieres usar el método de subscribe , usa algo como eso:

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

Para finalizar, si desea ejecutar ambas solicitudes en paralelo y recibir una notificación cuando todos los resultados sean entonces, debe considerar usar Observable.forkJoin (debe agregar la import 'rxjs/add/observable/forkJoin' ):

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