首页 > 解决方案 > 将 observable 返回的对象数组转换为另一种类型的数组

问题描述

情况是这样的:我有“任务服务”返回一个可观察的任务数组:

  getMissions(): Observable<Mission[]> {
  return this.http.get<Mission[]>(this.MissionUrl).pipe(
    tap(_ => this.log('Fetched missions.')),
    catchError(this.handleError('getMissions: ', []))
  );

以及组件内这个完美运行的订阅者功能:

export class TreeViewerComponent implements OnInit {
  missions: Mission[];
  Nodes: Node[]=[];
  Edges: Edge[];

  constructor(private missionService: MissionService,
              private messageService: MessageService) { }

  ngOnInit() {
      this.getNodes();

  }

    getNodes(): void {
      this.missionService.getMissions()
      .subscribe(missions => {
          this.missions = missions;
          this.doThis();
        })
}

    doThis(): void{
      console.log('tree-viewer component1: '+this.missions);
      for (var i=0;i<this.missions.length;i++)
      {
        var tempNode= {id: this.missions[i].key, label: this.missions[i].Title};
        console.log(tempNode);
        this.Nodes.push(tempNode);
      }
      this.getEdges();
      this.wrapData();
    }

问题是,它不是一个很好的关注点分离。查看器组件不应该处理所有这些业务逻辑。我想将类型转换与任务类型(从远程服务器返回)分开,以将 Node 类型输入另一个服务。

我怎样才能做到异步?

实施建议后编辑:

我仍然在做错事。正如建议的那样,我在 treeHandlerService 中有两个版本的 getNodes 方法。第一个是 @fmontes 建议的实施,它确实有效:

  getNodes(): void
  {
    this.missionService
        .getMissions()
        .pipe(
            flatMap((missions: Mission[]) => missions), // this will pass each mission to the map
            map((mission: Mission) => { // this will turn each Mission into a Node
                return new Node(mission.key, mission.Title) ;
            }),
            toArray() // this will group the nodes into an array of nodes
        )
        .subscribe((nodes: Node[]) => {
            this.Nodes = nodes;
            this.log('nodes: '+this.Nodes[0].label);//the log shows that it is working!
        });
  }

唉,当我去组件读取treeHandlerService.Nodes(异步更新的数组)时,它仍然是未定义的(意味着异步活动还没有完成)。

另一个版本是缩短版本,我尝试立即返回该值:

  getNodes(): Observable<Node[]> {
    return this.missionService.getMissions().pipe(
      map((mission: Mission) => { // this will turn each Mission into a Node
          return new Node(mission.key, mission.Title) ;
      }),
      toArray()
    )
  };

但它甚至没有编译!我收到以下错误:

ERROR in src/app/tree-handler.service.ts(39,7): error TS2345: Argument of type 'OperatorFunction<Mission, Node>' is not assignable to parameter of type 'OperatorFunction<Mission[], Node>'.

类型“任务”不能分配给类型“任务 []”。“任务”类型中缺少属性“长度”。

请帮助各位...

标签: angularrxjsangular-servicesangular2-observables

解决方案


我认为它可以像这样进一步简化:

import { map, catchError } from 'rxjs/operators';

export class MissionService {

  ...

  getMissions(): Observable < Mission[] > {
    return this.http.get < Mission[] > (this.MissionUrl).pipe(
      map(missions => missions.map(mission => ({ 
        id: mission.key,
        label: mission.Title }) 
      )),
      catchError(this.handleError('getMissions: ', []))
    );
  }

  ...

}

在这里,我没有额外使用flatMapandtoArray运算符,而是简单地使用mapRxjs 的运算符和map数组上的方法来完成必要的操作。

然后在您的组件类中:

export class TreeViewerComponent implements OnInit {
  missions: Mission[];
  Nodes: Node[] = [];
  Edges: Edge[];

  constructor(
    private missionService: MissionService,
    private messageService: MessageService
  ) {}

  ...

  getNodes(): void {
    this.missionService.getMissions()
      .subscribe(missions => {
        this.missions = missions;
      });
  }

  ...

}

推荐阅读