【问题标题】:Simple filter on array of RXJS ObservableRXJS Observable 数组上的简单过滤器
【发布时间】:2016-10-25 19:02:24
【问题描述】:

我正在使用 Angular2 开始我的项目,开发人员似乎推荐 RXJS Observable 而不是 Promises。

我已经实现了从服务器检索元素列表(史诗)。 但是如何使用例如 id 来过滤元素?

以下代码是从我的应用程序中提取的,现在显示了最终的工作解决方案。让我们希望它对某人有所帮助。

@Injectable()
export class EpicService {

  private url = CONFIG.SERVER + '/app/';  // URL to web API

  constructor(private http:Http) {}

  private extractData(res:Response) {
    let body = res.json();
    return body;
  }

  getEpics():Observable<Epic[]> {
    return this.http.get(this.url + "getEpics")
      .map(this.extractData)
      .catch(this.handleError);
  }

  getEpic(id:string): Observable<Epic> {
    return this.getEpics()
      .map(epics => epics.filter(epic => epic.id === id)[0]);
  }
}

export class EpicComponent {

  errorMessage:string;
  epics:Epic[];
  epic:Epic;

  constructor(
    private requirementService:EpicService) {
  }

  getEpics() {
    this.requirementService.getEpics()
      .subscribe(
        epics => this.epics = epics,
        error => this.errorMessage = <any>error);
  }

  // actually this should be eventually in another component
  getEpic(id:string) {
    this.requirementService.getEpic(id)
        .subscribe(
        epic => this.epic = epic,
        error => this.errorMessage = <any>error);
  }
}

export class Epic {
  id: string;
  name: string;
}

提前感谢您的帮助。

【问题讨论】:

  • 你应该保留原来的问题,这样我们就永远不知道“不”做什么

标签: javascript typescript angular rxjs observable


【解决方案1】:

带有修复的原始答案: Observables 很懒惰。你必须打电话给subscribe 告诉observable 发送它的请求。

  getEpic(id:number) {
    return this.getEpics()
           .filter(epic => epic.id === id)
           .subscribe(x=>...);
  }

更新到 Rxjs 6:

import {filter} from 'rxjs/operators';

getEpic(id:number) {
        return this.getEpics()
               .pipe(filter(epic => epic.id === id))
               .subscribe(x=>...);
      }

【讨论】:

  • subscribe的返回类型是一个Subscription,它实现了ISubscription。两者都没有过滤方法。
  • @StefanRein,在原始问题 this.getEpics() 返回一个 Array 的 observable。所以,filterArray 的方法
  • 你是对的。就在您的回答中,您将过滤器链接在订阅方法之后,该方法没有过滤器方法,因此我的评论
【解决方案2】:

您需要过滤实际的数组,而不是围绕它的 observable。 因此,您会将 Observable 的内容(即 Epic[])映射到过滤后的 Epic

getEpic(id: string): Observable<Epic> {
  return this.getEpics()
     .map(epics => epics.filter(epic => epic.id === id)[0]);
}

然后你就可以subscribegetEpic 做任何你想做的事情。

【讨论】:

  • 看起来很简单,但是:错误:(33, 42) TS2365:运算符“===”不能应用于“字符串”和“数字”类型。我将更新问题,以显示整个组件和服务关系。
  • 好吧,如果是这样,那么您可以从字符串转换为数字或从数字转换为字符串:)
【解决方案3】:

您必须订阅 Observables 才能获取数据,因为 http 调用在 JavaScript 中是异步的。

getEpic(id: number, callback: (epic: Epic) => void) {
    this.getEpics().subscribe(
        epics: Array<Epic> => {
            let epic: Epic = epics.filter(epic => epic.id === id)[0];
            callback(epic);
        }
    );
}

您可以像这样调用该方法:

this.someService.getEpic(epicId, (epic: Epic) => {
    // do something with it
});

【讨论】:

    【解决方案4】:

    您可以使用ObservableflatMapfilter 方法而不是map 中的JS 数组过滤方法来做到这一点。比如:

    this.getEpics() 
        .flatMap((data) => data.epics) // [{id: 1}, {id: 4}, {id: 3}, ..., {id: N}]
        .filter((epic) => epic.id === id) // checks {id: 1}, then {id: 2}, etc
        .subscribe((result) => ...); // do something epic!!!
    

    flatMap 将为过滤提供奇异索引,然后您可以继续处理接下来发生的任何结果。

    如果 TypeScript 抛出错误,表明您无法比较字符串和数字,无论您在过滤器中使用 ==,只需在过滤器中的 epic.id 之前添加一个 +,根据 Angular 文档:

        .flatMap(...)
        .filter((epic) => +epic.id === id) // checks {id: 1}, then {id: 2}, etc
        .subscribe(...)
    

    示例:

    https://stackblitz.com/edit/angular-9ehje5?file=src%2Fapp%2Fapp.component.ts

    【讨论】:

    • 这比公认的答案干净得多,并且充分利用了 Rx。正如作者指出的那样,执行此操作的正确方法是使用flatMap
    • 如果史诗是一个数组(如你所建议的那样),则不能将平面映射到data.epics。而且你也不能像你写的那样过滤数组。
    • @StefanRein 我认为您应该先试用代码然后发表评论 - stackblitz.com/edit/…
    • @mtpultz 是的,我确实从 SO 复制了您的评论作为输入。您对 SO 上的 getEpics() 方法的评论应该是:// { epics: [{id: 1}, {id: 2}, {id: 3}, {id: 4}, {id: 5}] } 而不是像 Stackblitz 示例中的 // [{id: 1}, {id: 4}, {id: 3}, ..., {id: N}] ......这让我很困惑,谢谢。也应该查看 Stackblitz 示例:)
    • 我已将评论下移了一行
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-12
    • 1970-01-01
    • 2023-04-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多