在Angular 7中使用expand()和concatMap()进行递归

时间:2019-05-31 15:37:35

标签: javascript angular typescript rxjs

我下面有以下API列表:

1. https://www.something.com/?filter=something

Result: 
{ 
  id: 12
  previous: null
  next: https://www.something.com/?filter=something&page=2
  data: ...
}

2. https://www.something.com/?filter=something&page=2

Result: 
{ 
  id: 13
  previous: https://www.something.com/?filter=something
  next: https://www.something.com/?filter=something&page=3
  data: ...
}

3. https://www.something.com/?filter=something&page=3

Result: 
{ 
  id: 14
  previous: https://www.something.com/?filter=something&page=2
  next: null
  data: ...
}

我想在获取每个API调用的数据后循环遍历所有url,请检查下一个变量是否为null。如果不为null,它将继续继续。在处理过程中,每个API调用的数据将是concat并返回到输出。

这是我到目前为止一直在尝试的

 getByURL(url: string): any {
    return this.apiService.get(url).pipe(map(data => data));
  }

  getData(): Observable<any> {
    const url = 'https://www.something.com/?filter=something';
    return this.getByURL(url).pipe(
      expand(({ data }) => {
        if (!data.next) return this.getByURL(data.next);
        else return empty();
      }),
      concatMap(({ content }) => {
        return of(content.data);
      })
    );
  }

但是我得到了不确定的结果,我已经努力了好几天。谢谢

已更新

我将代码放在stackblitz中: 我有3个api调用:

http://5cf15627c936cb001450bd0a.mockapi.io/users
http://5cf15627c936cb001450bd0a.mockapi.io/users2
http://5cf15627c936cb001450bd0a.mockapi.io/users3

我想在每次请求后收集所有数据。请查看控制台以查看输出。我总是不确定。谢谢

https://stackblitz.com/edit/angular-rai6az?file=src%2Fapp%2Fapp.component.ts

1 个答案:

答案 0 :(得分:1)

我将您的代码固定如下(fixed stackblitz

  ngOnInit() {
    this.getByPageNext()
      .subscribe(data => {
        console.log(data);
      });
  }

  get(url: string): Observable<any> {
    return this.httpClient
      .get(url)
      .pipe(catchError(this.formatErrors));
  }

  formatErrors(error: any) {
    console.error('error', error);
    return throwError(error.error);
  }

  getByURL(url: string): any {
    return this.get(url);
  }

  getByPageNext(): Observable<any> {
    const url = 'https://5cf15627c936cb001450bd0a.mockapi.io/users2';
    return this.getByURL(url)
      .pipe(
        expand((response: Array<any>) => {
          if (response && response.length && response[0].next) {
              return this.getByURL(response[0].next);
          }
          else {
            return empty()
          }
        }),
        map(obj => obj[0]), 
        reduce((acc, x: any) => acc.concat([x.data]), []),
      );
  }

因此它将连接所有数据作为数组,并且递归调用http可以正常工作。

唯一的问题是,当调用'https://5cf15627c936cb001450bd0a.mockapi.io/users'时,下一个URL是http而不是https,这将导致HttpError-> ProgressEvent。

所以我从表格'https://5cf15627c936cb001450bd0a.mockapi.io/users2'开始,其余的工作正常。因此,在您更改了后端以修复下一个链接后,然后将其更改回原始请求。

另一点是您从api返回的结果是数组而不是对象,这就是为什么我访问result[0]

另一点是您要返回empty()的条件,反之亦然