Angular - 如何为多个http请求实现switchMap?

Angular - How to implement switchMap for multiple http requests?

在我的项目中,有时我想在用户更改另一个列表中的选定值时更新列表中的可用选项。为此,我将 valueChangespipe 运算符和 switchMap 一起使用,如下所示:

this.form.controls.typeControl.valueChanges
  .pipe(
    switchMap((typeId: number) => {
      return this.typesService.getProjectsByType(typeId);
    }),
  )
  .subscribe((projects) => {
    //...
  });

现在我遇到了一个问题,我需要一次执行两个 http 请求来更新多个列表而不是一个。当我尝试添加第二个 switchMap 时,我得到 error TS2345: Argument of type 'OperatorFunction<number, Project[]>' is not assignable to parameter of type 'OperatorFunction<any, number>'. 以下是我尝试这样做的方法:

this.form.controls.typeControl.valueChanges
  .pipe(
    switchMap((typeId: number) => {
      return this.typesService.getProjectsByType(typeId);
    }),
    switchMap((typeId: number) => {
      return this.typesService.getProgramsByType(typeId);
    }),
  )
  .subscribe(([projects, programs]) => {
    //...
  });

如何在此处添加第二个 http 请求,以便处理 subscribe 中两个请求收到的数据?

forkJoin 运算符在这里可以提供帮助,您可以这样做:

this.form.controls.typeControl.valueChanges
  .pipe(
    switchMap((typeId: number) => {
     return forkJoin([
       this.typesService.getProjectsByType(typeId),
       this.typesService.getProgramsByType(typeId)
      ])
    })
  )
  .subscribe(([projects, programs]) => {
    //...
  });

您可以使用 combineLataestforkJoin 创建一个在其中一个源发出时发出的 observable:

this.form.controls.typeControl.valueChanges.pipe(
    switchMap(typeId => combineLatest([
      this.typesService.getProjectsByType(typeId),
      this.typesService.getProgramsByType(typeId)
    ]))
  )
  .subscribe(([projects, programs]) => {
    // ...
  });

但是,如果这两个数据(projectList 和 programList)彼此不相关,您可能会发现将它们定义为单独的可观察对象更方便:

private typeId$ = this.form.controls.typeControl.valueChanges;

projectList$ = this.typeId$.pipe(switchMap(id => this.typesService.getProjectsByType(id)));
programList$ = this.typeId$.pipe(switchMap(id => this.typesService.getProgramsByType(id)));

这可以为您提供更精细的控制,并允许您更轻松地在模板中使用 async 管道:

    <h1> Projects </h1>
    <ul> 
        <li *ngFor="let project of projectList$ | async">
            {{ project.name }}
        </li>
    </ul>

    <h1> Programs </h1>
    <ul> 
        <li *ngFor="let program of programList$ | async">
            {{ program.name }}
        </li>
    </ul>