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:
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]; });