2016-07-22 13 views
2

Auf der Suche nach Hilfe mit einer Observable HTTP-Sequenz, möchte ich zwei HTTP-Aufrufe an eine API, die zweite abhängig von der ersten. Die erste gibt ein Array von URLs zurück und die zweite ruft Anfragen für jede URL in diesem Array ab und gibt dann die Antworten im Stream zurück. Wenn ich hart Code in einem der abhängigen Anfrage wie so erhalten, den ich wieder der Titel ich suche:Angular 2 chained Http Anfragen mit Iterable Array

search(character): Observable<any> { 
let that = this 
let queryUrl: string = character.url; 
return this.http.get(queryUrl) 
    .map((response: Response) => { 
    this.characterResults = response.json().films 
    return this.characterResults 
     //Example response: 
     // ["https://api.com/films/1", "https://api.com/films/2", "https://api.com/films/3", "https://api.com/films/4"] 
    }) 
    .flatMap((film) => { 
    return that.http.get(film[0]) 
    .map((response: Response) => { 
     return response.json().title 
    }) 
    }) 
} 

getApiData(character) { 
    this.apiService.search(character) 
    .subscribe((results) => { // on sucesss 
      console.log(results) 
     }, 
     (err: any) => { // on error 
      console.log(err); 
     }, 
     () => { // on completion 
      console.log('complete') 
     } 
    ); 

aber jeder Versuch, mit forEach über das Array zu durchlaufen und dann alle http Anrufe gibt mir dieser Fehler:

browser_adapter.js:84 EXCEPTION: TypeError: Cannot read property 'Symbol(Symbol.iterator)' of undefined 

Idealerweise würde ich eine elegante Art und Weise wie diese spätere Anrufe parallel zu dem Ergebnis Array aus dem ersten Aufruf zu machen, aber ich kann nicht, welche von rxJs die Dutzende von Methoden scheinen, um herauszufinden mir helfen könnte TU es. Kann mir jemand Hilfe anbieten?

+0

'flatMap' soll Observable zurückgeben, aber Ihr Code gibt nichts zurück. Vielleicht ist das das Problem. –

+0

Code wurde aktualisiert, Sie hatten Recht darüber –

Antwort

5

Zwei Möglichkeiten, wenn Sie möchten, dass jedes der Ergebnisse einzeln gestreamt wird, dann ist flatMap Ihr Freund. Sie können es verwenden, um fast alles abzuflachen, Arrays, Promises oder Observables. In Ihrem Fall können Sie die Kette die Anfrage zusammen, indem Sie:

search(character): Observable<any> { 
    return this.http.get(character.url) 
    .flatMap((response: Response) => response.json().films) 
    .flatMap((film: string) => this.http.get(film), 
      (_, resp) => resp.json().title) 
} 

getApiData(character) { 
    this.apiService.search(character) 
     .subscribe((results) => { // on sucesss 
      //Called for each url result 
      console.log(results) 
     }, 
     (err: any) => { // on error 
      console.log(err); 
     }, 
     () => { // on completion 
      console.log('complete') 
     } 
    ); 

Oder können Sie forkJoin verwenden, anstatt eine Reihe von Ergebnissen

return this.http.get(character.url) 
    .flatMap((response: response) => 
      //Waits until all the requests are completed before emitting 
      //an array of results 
      Observable.forkJoin(response.json().files.map(film => 
       this.http.get(film).map(resp => resp.json().title) 
      )); 

bearbeiten 1

Um der zweite zurückzukehren Argument von flatMap vollständiger. Es ist eine Funktion, die den ursprünglichen Wert empfängt, der an die erste Selektormethode übergeben wurde, gepaart mit einem Ergebnis der Glättungsoperation. Dies ist der Fall, wenn Selektor 1 a empfängt und einen Observable von [1, 2, 3] zurückgibt. Der zweite Selektor würde dreimal mit Argumenten (a, 1), (a, 2) und (a, 3) aufgerufen.

Wenn Sie mehrere Werte erhalten möchten, würde ich vorschlagen, dass Sie einen sekundären Mapping-Operator verwenden, um den Fluss sauber zu halten, aber es liegt an Ihnen.

.flatMap((film: string) => this.http.get(film), 
     (film: string, resp: Response) => resp.json()) 
//Typescript's destructuring syntax, extracts the values you want 
//and creates a new object with only those fields 
.map(({date, title}) => ({date, title})); 
+0

danke! Der erste Fall passt zu meinem Anwendungsfall und ist sehr elegant und funktioniert. Ich bin mir nicht sicher, ob ich die zweite flatMap verstehe. '.flatMap ((Film: string) => this.http.get (Film), (_, resp) => resp.json(). title) }' was ist '(_, resp)' tun? Und ich bin mir nicht sicher, ob ich verstehe, wie Sie den HTTP-Return mit nur einem Komma abbilden, die Syntax verwirrt mich. –

+0

'flatMap' nimmt zwei Argumente, das erste gibt ein Objekt zum Reduzieren zurück und das zweite nimmt die einzelnen Werte aus der abgeflachten Quelle und wendet ein Mapping auf sie an. In diesem Fall nimmt es die Antworten von jedem HTTP-Aufruf und extrahiert den Titel aus dem Antwortwert. – paulpdaniels

+0

Danke Paul! Wenn ich den Titel und ein Datum aus dem Objekt extrahieren und ein Array von Objekten ausgeben möchte: [{title: 'resp.json(). Title', date: 'rsp.json(). Date'}, { title: 'title, date:' date '}], das ich * ngFor verwenden könnte, um Async in einer Komponente anzuzeigen, wäre das möglich? –