Concatenamento di osservabili RxJS da dati http in Angular2 con TypeScript

Attualmente sto cercando di insegnarmi Angular2 e TypeScript dopo aver lavorato felicemente con AngularJS 1. * negli ultimi 4 anni! Devo ammettere che lo odio ma sono sicuro che il mio momento di eureka è dietro l’angolo … comunque, ho scritto un servizio nella mia app fittizia che recupererà i dati http da un backend fasullo che ho scritto che serve 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'); } } 

Ora in un componente desidero eseguire (o concatenare) entrambi i getUserInfo() e getUserPhotos(myId) . In AngularJS questo è stato facile, come nel mio controller avrei fatto qualcosa del genere per evitare la “Pyramid of doom” …

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

Ora ho provato a fare qualcosa di simile nel mio componente (sostituendo .then per .subscribe ) tuttavia la mia console degli errori impazziva!

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

Ovviamente sto facendo qualcosa di sbagliato … come farei meglio con Observables e RxJS? Scusa se ti sto facendo domande stupide … ma grazie per l’aiuto in anticipo! Ho anche notato il codice ripetuto nelle mie funzioni quando dichiaro le mie intestazioni http …

Per il tuo caso d’uso, penso che l’operatore flatMap sia ciò di cui hai bisogno:

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

In questo modo, eseguirai la seconda richiesta una volta ricevuta la prima. L’operatore flatMap è particolarmente utile quando si desidera utilizzare il risultato della richiesta precedente (evento precedente) per eseguirne un altro. Non dimenticare di importare l’operatore per poterlo usare:

 import 'rxjs/add/operator/flatMap'; 

Questa risposta potrebbe darti maggiori dettagli:

  • HTTP GET angular con errore TypeScript http.get (…). Map non è una funzione in [null]

Se vuoi usare solo il metodo subscribe , usi qualcosa del genere:

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

Per finire, se si desidera eseguire entrambe le richieste in parallelo e ricevere una notifica quando tutti i risultati sono allora, si dovrebbe considerare di utilizzare Observable.forkJoin (è necessario aggiungere import 'rxjs/add/observable/forkJoin' ):

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