使用自定义过滤器和订阅时未更新 ngFor 列表

TKi*_*hvi 0 rxjs angular

我制作了一个搜索组件,它有一个输入字段,可以在输入时过滤搜索结果列表。我还有一个 websocket,可以将新的或更改的值推送到列表中,如下所示:

this._fooService.foos.subscribe(foos => {
    this.foos = foos;
});
Run Code Online (Sandbox Code Playgroud)

当我更改过滤器搜索词时没有过滤器和列表更新时,这很好用。在模板中,它很简单:

<div *ngFor="let foo of foos | filterFoos: searchTerm">
Run Code Online (Sandbox Code Playgroud)

我试过这样做:NgFor 不使用 Angular2 中的管道更新数据

但它没有奏效。我的另一个视图中有相同类型的带有条形的搜索组件,它与过滤器一起工作得很好。虽然有一个承诺,需要在 this.bars = bar 运行之前完成。


编辑:

_fooService.foos 是 Observable<Foo[]>并且在构造函数中初始化:

this.foos = this._fooObservable.asObservable(); 
Run Code Online (Sandbox Code Playgroud)

其中 _fooObservable 是 BehaviorSubject<Foo[]>并且使用 .next 方法(以及旧的 Foos)向其中添加新的 Foos。

过滤管是这样的:

@Pipe({name: 'filterFoos'})
export class FilterFoosPipe implements PipeTransform {

  transform = (foos: Foo[], searchTerm: string = ""): any => {
    let filtered = foos.filter((foo) => {
        return foo.name.toLowerCase().includes(searchTerm.toLowerCase())
    });
    return filtered;
  }
}
Run Code Online (Sandbox Code Playgroud)

ols*_*lsn 5

由于您有一个流,您可以使用async-pipe:

<div *ngFor="let foo of _fooService.foos | async | filterFoos: searchTerm">
Run Code Online (Sandbox Code Playgroud)

这样你甚至可以在你的控制器中删除你的自定义订阅,这无论如何都容易发生内存泄漏。异步管道应自动触发 UI 中的更新。


需要注意的第二件事是 ngZone - 在极少数情况下,一些存储更新是在 ngZone 之外触发的,因此不会触发更改检测周期,这可以通过将更新显式包装在ngZone.run 中来解决:

ngZone.run(() => doMyStoreUpdate(...));
Run Code Online (Sandbox Code Playgroud)