【问题标题】:Nested ApiCalls with Angular HttpClient and RxJS使用 Angular HttpClient 和 RxJS 的嵌套 ApiCall
【发布时间】:2018-11-08 12:59:04
【问题描述】:

所以,我有服务器,它根据请求返回对象数组

例子:

[
  {
   id: 1
   name: name1
  },
  {
   id: 2
   name: name2
  }
]

数组可以有无限个元素;

之后,我必须为数组中的每个元素发送新的请求,并带有响应 ID。

示例:

https://localhost/api/parent/${id}/child

回复:

[
  {
   childId: 1
   name: name1
  },
  {
   childId: 2
   name: name2
  },
  {
   childId: 3
   name: name3
  }
]

然后我必须为每个新请求的响应发送新请求

示例:

https://localhost/api/parent/${id}/child/${childId}/grandChild

回复:

[
  {
   grandChildId: 1
   name: name1
  },
  {
   grandChildId: 2
   name: name2
  },
  {
   grandChildId: 3
   name: name3
  }
]

反应和其他人一样

然后我必须组织数据看起来像这样

[
  {
   id: 1
   name: name1
   children: [
            {
              childId: 1
              name: name1,
              grandChildren: [
                            {
                             grandChildId: 1
                             name: name1
                            },
                            {
                             grandChildId: 2
                             name: name2
                            },
                            {
                             grandChildId: 3
                             name: name3
                            }
                            ]
            },
            {
             childId: 2
             name: name2
            },
            {
            childId: 3
            name: name3
            }
        ]
  },
  {
   id: 2
   name: name2
  }
]

每个父母都有一组孩子,每个孩子都有一组孙子。

这是我的尝试,但如果我尝试在组件中执行 parents.forEach(parent => console.log(parent.childern)) 它是未定义的

getData() {

return this.http.get<Parent[]>(baseUrl + 'parent', {withCredentials: true}).pipe(
      map(parents => {
        parents.forEach(parent => {
          this.getChildren(parent).subscribe(Children => {
            parent.Children = Children;
            parent.Children.forEach(Children => {
              this.getGrandChildren(Children).subscribe(grandChild => {
                Children.grandChildren = grandChild;
              });
            });
          });
        });
      return parents;
      })
        );

}

 getChildren(parent: Parent): Observable<Child[]> {
  return this.http.get<Children[]>(baseUrl + `parent/${parent.id}/children`, {withCredentials: true});

}

 getGrandChildren(child: Child): Observable<GrandChild[]> {
return this.http.get<GrandChild[]>(baseUrl + `children/${child.id}/GrandChildren`, {withCredentials: true});

}

【问题讨论】:

    标签: angular rxjs observable angular6


    【解决方案1】:

    查看您的问题,它似乎具有递归性质。

    ParentChildGrandChild 都是相似的,看起来像一棵树的节点和叶子的平面表示。如果是这种情况,您可以查看this,了解有关如何使用 RxJS 进行递归处理的一些详细信息。

    严格按照您提出问题的方式,至少在我的理解范围内,这是解决问题的方法

    getParents()
    .pipe(
      switchMap(parents => from(parents)),
      mergeMap(parent => getChildren(parent)
        .pipe(
          switchMap(children => from(children)),
          mergeMap(child => getGrandChildren(child)
            .pipe(
              tap(grandChildren => child.grandChildren = grandChildren),
              map(() => child)
            )
          ),
          toArray(),
          tap(children => parent.children = children),
          map(() => parent)
        ), 1  // cuncurrency set to 1 to guarantee same order
      ),
    )
    .subscribe(d => console.log(JSON.stringify(d, null, 2)))
    

    我用下面的模拟数据和函数测试过

    const parents = [
      {id: 1, name: 'name1'},
      {id: 2, name: 'name2'},
    ];
    const children = [
      {childId: 1, name: 'name1'},
      {childId: 2, name: 'name2'},
      {childId: 3, name: 'name3'},
    ];
    const grandChildren = [
      {grandChildId: 1, name: 'name1'},
      {grandChildId: 2, name: 'name2'},
      {grandChildId: 3, name: 'name3'},
    ];
    
    function getParents(): Observable<Parent[]> {
      return of(parents).pipe(delay(10));
    }
    function getChildren(parent: Parent): Observable<Child[]> {
      return (parent.id === 1 ? of(children) : of([])).pipe(
        delay(100)
      );
    }
    function getGrandChildren(child: Child): Observable<GrandChild[]> {
      return (child.childId === 1 ? of(grandChildren) : of([])).pipe(delay(1000));
    }
    

    【讨论】:

    • 谢谢兄弟!它解决了我的问题。一个小问题,数据没有按正确的顺序排列,但我可以排序!
    • 我的顺序不正确,因为我放了一些延迟以使其更真实,以防您必须通过异步 API 从远程系统获取这些数据。您可以将第一个mergeMap 替换为concatMap 或在第一个mergeMap 中再次添加1 作为concurrency 参数来解决问题。我已经用第二个选项更新了我的回复。
    • 是的,我发现它应该使用 concatMap,也必须在末尾添加 toArray(),因为它返回的是单个对象。感谢您的帮助!!!
    【解决方案2】:

    你可以这样做:

     getRoot() {
        return this.http.get<Parent[]>(baseUrl + 'parent', {withCredentials: true}).pipe(
          switchMap(items => forkJoin(items.map(i => this.getChild(i))))
        )
      }
    
      getChild(parent) {
        return this.http.get<Children[]>(baseUrl + `parent/${parent.id}/children`, {withCredentials: true}).pipe(
          switchMap(items => forkJoin(items.map(i => this.getGrandChild(i)))),
          map(resp => (parent.children = resp, parent))
        );
    
      }
    
      getGrandChild(parent) {
        return this.http.get<GrandChild[]>(baseUrl + `children/${child.id}/GrandChildren`, {withCredentials: true}).pipe(
          map(resp => (parent.grandChildren = resp, parent))
        )
      }
    

    使用items.map 将结果数组转换为相关子项的请求数组。

    然后它使用forkJoin将所有这些请求加入到 1 个 Observable 中

    然后它使用switchMap 发出请求,并使用map 将子代添加到响应中。

    Here is a Stackblitz to demonstrate

    【讨论】:

      【解决方案3】:

      你会混淆大写和小写吗?使用约定能够识别某些东西。

      试试parent.children

      【讨论】:

        【解决方案4】:

        HttpClient 将返回 Observable&lt;any&gt; 数据,因此您不能只使用 mapoperator 读取数据,而是尝试循环遍历 Observable&lt;any&gt;

        要从此函数获取数据 - this.getData(),您需要从您的组件类中访问它,例如 this.getData().subscribe((res) =&gt; {console.log(res)}),现在您可以在控制台中查看数据

        所以现在循环遍历数组并调用另一个服务函数 - 确保所有 parent childrengrandChildren 都有单独的函数,否则有一个通用的 http.get() 函数并将 URL 传递给获取数据 - 这不是嵌套 HttpClient 调用的最佳方式

        希望你理解 - 快乐编码

        【讨论】:

          猜你喜欢
          • 2017-03-20
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-11-02
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多