Angular - 如何在数组中映射可观察对象

Angular - how to map observable inside array

我有一个 servers 对象数组,在该数组中我有另一个可观察的对象数组,它的键是 [securityGroups] .

ngOnInit(): void {
    forkJoin(
      this.serverService.getServer(),
      this.securityGroupService.getSecurityGroups())
      .pipe(takeWhile(() => this.alive))
      .subscribe(([servers, groups]) => {
        this.servers = servers.map((item) => ({
          ...item,
          securityGroups: this.serverService.getServerById(item.id)
            .pipe(map(server => server["security_groups"]))
        }))
        this.securityGroupArray = groups['security_groups'].map((item) => ({
          ...item,
          expanded: false,
        }))
      }

如何从我的服务器阵列映射此 [securityGroup] 密钥?因为它是一个 Observable。我不想在 html 中创建一个异步管道,我想将它保存在一个新数组中

我的服务器阵列负载:

[{id: "1879f47f-1c5e-464b-bb76-e7cc13ef426e", name: "hello", flavor: {…}, securityGroups: Observable}
,
{id: "b9c7e32a-bf99-4250-83cb-13523f9c1604", name: "test01", flavor: {…}, securityGroups: Observable}]

您可以使用 forkJoin 解析所有内部可观察对象并将其映射到 server 对象的 securityGroups 属性

this.serverService.getServer()
.pipe(switchMap((servers) => {
   return from(servers).pipe(mergeMap((server) => {
      return forkJoin(server.securityGroups)
      .pipe(map((_securityGroups) => {
         server.securityGroups =_securityGroups
         return server;
      }))
   }))
}))

如果我理解正确,你的挑战是你收到了一个 servers 数组,你需要为每个数组调用以检索更多数据 (securityGroups) 并将其附加到对象。

为此,您需要以某种方式“订阅”此辅助调用,以便接收数据。有几个"Higher Order Mapping Operators" that can do this for you, so you don't have to deal with nested subscriptions. In this case, we can use switchMap.

为了一次进行一堆调用,我们可以使用 forkJoin 一次进行所有调用并接收所有结果的数组。

您目前正在使用 forkJoin 进行 2 次不同的调用,但您并未将这些调用的结果用于同一目的。我会将它们分成单独的可观察对象,既为了意图的清晰,也为了它们可以独立使用:

  securityGroups$ = this.securityGroupService.getSecurityGroups().pipe(
    map(groups => groups.map(group => ({
      ...group,
      expanded: false
    })))
  );

  servers$ = this.serverService.getServers().pipe(
    switchMap(servers => forkJoin(
      servers.map(s => this.serverService.getServerById(s.id))
    )
    .pipe(
      map(serversWithGroups => serversWithGroups.map((server, i) => ({
        ...servers[i],
        securityGroups: server.security_groups
      }))),
      // shareReplay(1) - see comment below
    ))
  );

如果需要,您仍然可以在控制器中订阅:

ngOnInit() {
    this.servers$.subscribe();
    this.securityGroups$.subscribe();
}

或者您可以在模板中使用 AsyncPipe

<ng-container *ngFor="let group of securityGroups$ | async">
    <option *ngFor="let server of servers$ | async" [value]="server.id">
        <ng-container *ngFor="let secGroup of server.securityGroups">
            {{ secGroup.name !== group.name ? server.name : '' }}
        </ng-container>
    </option>
</ng-container>

如果您正在嵌套 *ngFor,那么您可以使用 shareReplay() 运算符来防止多个订阅多次执行您的服务方法。