【问题标题】:RxJS Observables and the Right Way to architect filtered listsRxJS Observables 和构建过滤列表的正确方法
【发布时间】:2017-03-02 14:40:46
【问题描述】:

我已经阅读了很多教程,完成了演示等。但我仍然无法用正确的方法来使用 Observables 来做这件事......

基本上我拥有(角度)是我的组件中的 2 个可变数组,一个 displayList 和一个完整的项目列表...模板在 displayList 上执行 ngFor。

屏幕上的过滤器调用组件中的过滤器函数清除displayList,然后循环遍历fullList,如果过滤器适用,则将其推送到显示列表-在屏幕上提供实时列表过滤效果......

我知道这是处理此问题的错误方法,但我无法完全理解使用可观察对象执行此操作所需的架构/模式。我是否制作一个主列表并基于组件私有属性在其上运行 .filter() ?我是否对返回带有 .filter 的可观察列表的方法执行 ngFor?

提前致谢。

【问题讨论】:

  • 除非有一些你无法实现的功能,除非你使用 observables 我认为你的方法听起来不错。您可以为您的 displayList 创建一个 BehaviorSubject 例如displayList = new BehaviorSubject([]) 并使用 displayList.next(newDisplayList) 更新它。然后你可以在 ngFor 中使用*ngFor="item in displayList | async" 绑定它。但我不一定认为这种方法有好处

标签: angular rxjs observable


【解决方案1】:

是,是,不是,是,不是……换句话说:没有正确的答案,这取决于。 (根据您的个人偏好、一般用例、应用程序的现有架构等...)


在控制器中过滤

在你的情况下,可能不需要 rxjs,但你应该尽可能避免可变对象/数据,所以你使用 .filter 的想法将是这里的方法。


自定义管道

另一种方法是实现自定义管道并直接在模板中过滤数据:

<div *ngFor="let item of fullList | customFilterPipe:filterSettings">...</div>

RxJS 方式

既然你要求 rxjs-way,我会这样做:

filterSettings$: BehaviorSubject<IFilterData> = new BehaviorSubject(INITIAL_FILTER_SETTINGS); // this is updated with filterSettings$.next(newFilterSettings)
fullList$: BehaviorSubject<IData[]> = new BehaviorSubject([]); // updated through fullList$.next(newFullList);
displayList$ = Observable.combineLatest(this.fullList$, this.filterSettings$)
    .map(([list, filterSettings]) => {
        return list.filter(/* your custom filter based on the filterSettings... */);
    });

这将在filterSettings$fullList$ 更改时自动更新displayList$

要在模板中使用它,您可以使用async-Pipe:

<div *ngFor="let item of displayList$ | async">...</div>

但同样:这些解决方案中的任何一个以及您当前的实现都可能是给定案例的完全有效的实现。

【讨论】:

  • 谢谢,这正是我想要的
【解决方案2】:

在 RxJS 5 中,最好的候选者是 combineLatest() 运算符(它有静态和实例方法变体),当它的任何源 Observable 发出值时调用它的选择器函数。

let userInput$ = Observable.from(['a', 'ac', 'aca', 'acarp'])
  .concatMap(char => Observable.of(char).delay(500))
  .startWith(null);

let list$ = Observable.of(['abstemious', 'abstentious', 'abulia', 'abut', 'aby', 'acalculia', 'acarophobia', 'acarpous', 'accidence', 'accismus', 'acclamation']);

let filteredList$ = Observable.combineLatest(list$, userInput$, (list, filterString) => {
    if (filterString) {
      // Note that this is Array.filter() method, not an RxJS operator
      return list.filter(name => name.indexOf(filterString) === 0);
    }
    return list;
  });


filteredList$.subscribe(val => console.log(val));

观看现场演示:https://jsbin.com/jihuxu/2/edit?js,console

这模拟了用户每 500 毫秒键入一个字符并相应地过滤 list$ 的情况。请注意,list$ 也可以发出一个新数组,该数组将立即被过滤。

需要注意的重要一点是,每个源 Observable 必须至少发出一个值,然后.combineLatest() 才能在每次更改时发出。这就是为什么我还有startWith(null),以确保所选过滤器在开头是null

【讨论】:

    猜你喜欢
    • 2019-03-03
    • 2018-01-02
    • 2017-03-05
    • 1970-01-01
    • 1970-01-01
    • 2019-03-17
    • 2021-10-23
    • 2016-12-22
    • 1970-01-01
    相关资源
    最近更新 更多