2016-02-08 26 views
60

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.Concatenamento di osservabili RxJS da dati http in Angular2 con TypeScript

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 correre (o catena) sia getUserInfo() e getUserPhotos(myId) metodi. In AngularJS questo è stato facile come nel mio controller vorrei fare qualcosa di simile per evitare la "Piramide di sventura" ...

// 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 (sostituzione .then per .subscribe), tuttavia la mia console degli errori impazzisce!

@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 si dichiara miei intestazioni HTTP ...

risposta

99

Per il vostro caso d'uso, penso che l'operatore flatMap è quello che ti serve:

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

In questo modo, si vuole eseguire 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 dimenticate di importare l'operatore per essere in grado di usarlo:

import 'rxjs/add/operator/mergeMap'; 

Questa risposta potrebbe dare ulteriori dettagli:

Se si desidera utilizzare solo subscribe metodo, si utilizza 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 essere avvisati quando tutti i risultati sono poi, si dovrebbe prendere in considerazione 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]; 
}); 
+0

Tuttavia io capisco l'errore ' TypeError: source.subscribe non è una funzione in [null] ' –

+0

Dove si verifica questo errore? Quando si chiama 'this.userData.getUserInfo()'? –

+0

Da "Observable.forkJoin' –

Problemi correlati