使用Observables的map运算符

时间:2018-01-30 16:03:17

标签: angular observable

下面我在订阅后做了一个地图,但我想使用地图运算符。有人能指出我正确的方向吗?

  getChildren(node: any) {
    this.filter = {
      codedName: node.id
    };
    this.eclassService.getEclassNodes(this.filter)
    .subscribe(data => {
      console.log("data", data);
      data.map(child => {
        this.children.push({
          id: child.codedName,
          name: `${child.codedName} ${child.preferredName}`,
          hasChildren: true
        });
      });
    });
    // return this.asyncChildren.map((c) => Object.assign({}, c));
    return this.children.map((c) => Object.assign({}, c));
  }

3 个答案:

答案 0 :(得分:1)

首先要做的事情是:你的函数不应该异步修改this.children并同时返回它。让我们来看看你的代码(Tobiah的回答有同样的错误)。

  1. 您设置this.filter
  2. 您进行异步通话
  3. 您立即返回已映射的this.children
  4. 这是错误的,因为return不会等待异步调用完成。

    顺便说一下:

    Rx.Observable.from(this.eclassService.getEclassNodes(this.filter))
    

    这是多余的。它就像Object.assign({}),你正在使用它,也是多余的。

    而且,你的问题解释不够。您是否需要将数据保存在this.children中,或者您可以将其删除?

    我建议将getChildren函数设置为async,如下所示:

    interface Node {
      id: any;
      name: string;
      hasChildren: boolean;
    }
    
    getChildren(node: any): Observable<Node> {
      // is it necessary to bind this to state? it is suspicious side effect
      this.filter = {
        codedName: node.id
      };
    
      return this.eclassService.getEclassNodes(this.filter)
        .map((x: any[]) => 
          x.map(child => ({
            id: child.codedName,
            name: `${child.codedName} ${child.preferredName}`,
            hasChildren: true
          }))
        );
    }
    

    您需要了解的一个想法是, Observable.map会将您的函数应用于流中显示的每个对象。因此,如果您的流提供数组, Observable.map将在每个数组上应用函数,而不是在其元素上应用。所以你有类似(array) => doSmth(array)的东西。如果需要修改数组中的对象,则函数doSmth应该执行此操作。

    现在您可以订阅您的功能或在async管道的模板中使用它。

答案 1 :(得分:0)

Lukasz的回答对我有很大帮助,我设法解决它。

这是我完成的代码,考虑到Lukasz在答案中的提示。

我希望这可以帮助其他人,所以我附上完整的代码。

import { Component, OnInit } from "@angular/core";
import { ITreeOptions } from "angular-tree-component";
import { EclassService } from "../../services/eclass.service";
import "rxjs/add/operator/toPromise";
import "rxjs/add/operator/map";

@Component({
  selector: "app-async",
  template: `<tree-root #tree [options]="options" [nodes]="nodes"></tree-root>`,
  styles: ["async-tree-example.component.css"]
})

export class AsyncTreeExampleComponent implements OnInit {
  options: ITreeOptions = {
    getChildren: this.getChildren.bind(this)
  };
  nodes = [];
  children = [];

  constructor(private eclassService: EclassService) {}

  ngOnInit() {
    const filter: any = { level: "1" };
    this.eclassService.getEclassNodes(filter).subscribe(data => {
      this.nodes = data.map(item => {
        return {
          id: item.codedName,
          name: `${item.codedName} ${item.preferredName}`,
          hasChildren: true
        };
      });
    });
  }

  getChildren(node: any): Promise<object> {
    const filter = {
      codedName: node.id
    };

    return this.eclassService.getEclassNodes(filter)
      .map((x: any[]) => {
        return x.map(child => {
          if (child.level === "4") {
            return ({
              id: child.codedName,
              name: `${child.codedName} ${child.preferredName}`,
              hasChildren: false
            });
          } else {
            return ({
              id: child.codedName,
              name: `${child.codedName} ${child.preferredName}`,
              hasChildren: true
            });
          }
        });
      })
      .toPromise();
    }
  }

答案 2 :(得分:-1)

在查看documentation后,这似乎有效。

1)使用from

从Observable创建源

2)map到该源迭代,返回任何你想要的变异。

3)subscribe到该映射。

getChildren(node: any) {
  this.filter = {
    codedName: node.id
  };

  const source = Rx.Observable.from(this.eclassService.getEclassNodes(this.filter));

  const children = source.map(child => ({
    id: child.codedName,
    name: `${child.codedName} ${child.preferredName}`,
    hasChildren: true
  });

  children.subscribe((child) => {
    this.children.push(child);
  });

  return this.children.map((c) => Object.assign({}, c));
}