带有可变数组的Angular 2链式Http Get请求

时间:2016-07-22 03:12:39

标签: typescript angular rxjs observable angular2-http

寻找Observable http序列的帮助,我想对api进行两次http调用,第二次依赖于第一次。第一个返回一个Urls数组,第二个为该数组中的每个url生成get请求,然后返回流上的响应。如果我在其中一个依赖请求中硬编码,那么我会找回我正在寻找的一个标题:

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

但是任何尝试使用forEach迭代该数组然后进行所有http调用都会给我这个错误:

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

理想情况下,我希望有一种优雅的方法可以在第一次调用时将这些后续调用与结果数组并行,但我似乎无法弄清楚哪些rxJs的数十种方法可以帮助我做到这一点。任何人都可以给我任何帮助吗?

1 个答案:

答案 0 :(得分:5)

有两种方法,如果您希望每个结果都是单独流式传输,那么flatMap就是您的朋友。您可以使用它来展平任何内容,ArraysPromisesObservables。在您的情况下,您可以通过执行以下操作将请求链接在一起:

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

或者您可以使用forkJoin来返回结果数组

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

修改1

更完整地解决flatMap的第二个参数。它是接收传递给第一选择器方法的原始值的函数,该原始值与来自展平操作的结果配对。也就是说,如果选择器1收到a并返回Observable [1, 2, 3]。第二个选择器将使用参数(a,1),(a,2)和(a,3)调用3次。

如果您想获得多个值,我建议您使用辅助映射运算符来保持流清洁,但这取决于您。

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