【问题标题】:Angular async pipe don't refreshes result after input array filtering输入数组过滤后,角度异步管道不刷新结果
【发布时间】:2019-08-09 22:20:44
【问题描述】:

在父组件中,我有一个 Tour[] tours_filtered: Observable<Tour[]> 流,我在 http 请求的订阅函数中分配了它

this.api.getTours().subscribe(
  result => {
    this.tours_filtered = of(result.tours);
  }
)

在视图中我使用异步管道显示流

<app-tour-box [tour]="tour" *ngFor="let tour of tours_filtered | async"></app-tour-box>

到目前为止,所有工作都按预期进行。在一个子组件中,我有一个输入文本,它发出用户插入的值,以按标题过滤 Tour 数组。

在父组件中,我在函数中侦听发出的值,然后使用 switchMap 切换到按该值过滤的 Tour[] 新流

onSearchTitle(term: string) {
  this.tours_filtered.pipe(
    switchMap( 
      (tours) => of( tours.filter((tour) => tour.name.toLowerCase().includes(term)) )
    )
  )
}

我认为异步管道一直在监听以反映应用它的数组的更改,所以我认为我不必订阅上面的函数,但是当我输入时视图中没有任何变化过滤结果的输入。

如果我将新流分配给订阅函数中的原始数组,结果会正确更新

onSearchTitle(术语:字符串){ this.tours_filtered.pipe( switchMap((tours) => of(tours.filter((tour) => tour.name.toLowerCase().includes(term)))) ).订阅(val => { this.tours_filtered = of(val); }) }

这个程序正确吗?我可以避免订阅,因为我已经使用了异步管道吗?有更好的方法来实现我的目标吗?

编辑:

也许我找到了解决方案,我必须像这样重新评估变量的新流

onSearchTitle(term: string) {
    this.tours_filtered = of(this.city.tours).pipe(
      switchMap((tours) => of(tours.filter((tour) => tour.name.toLowerCase().includes(term))))
    );
  }

而且我不需要再次订阅,视图中的结果会根据用户输入的搜索词而变化。这是正确的方法吗?

【问题讨论】:

    标签: javascript angular observable


    【解决方案1】:

    我认为在您的情况下,解决方案应该如下工作:

    onSearchTitle(term: string) {
      this._searchTerm = term;
      this.tours_filtered = of( 
        this.city.tours.filter((tour) => tour.name.toLowerCase().includes(term))
      )
    }
    

    因为在您的示例中,您不会更改 ngFor 中使用的 observable。因此它不起作用。

    但是,我看不出这里使用 observables 的原因,除非这是第一步,并且您将来要从服务器获取这些数据


    更新

    对您而言,最好的解决方案是将您的输入视为可观察的并注意变化:

    // your.component.ts
    export class AppComponent  {
    
      searchTerm$ = new BehaviorSubject<string>('');
      results = this.search(this.searchTerm$);
    
      search(terms: Observable<string>) {
        return terms
          .pipe(
            debounceTime(400),
            distinctUntilChanged(),
            switchMap(term => {
              return of(this.city.tours.filter((tour) => tour.name.toLowerCase().includes(term)))
            }
            )
          )
      }
    
    }
    
    // your.template.html
    ...
    <input type="" (input)="searchTerm$.next($event.target.value)">
    ...
    

    此外,添加debounceTimedistinctUntilChanged 会更好,以获得更好的用户体验和更少的搜索请求。

    详情请见full example。更详细的解释请参考this article

    【讨论】:

    • 对不起,我的错误,在原始版本中,swithMap 运算符是switchMap((tours) =&gt; of(tours.filter((tour) =&gt; tour.name.toLowerCase().includes(term)))),但没有工作,我使用 observable 来利用 switchMap 的性质,它在用户键入时取消先前的请求要搜索的文本
    • 如果输入与其他逻辑在同一个组件中,但它位于一个子组件中,我已经收集了所有可能的过滤器来应用,那么您的解决方案非常好。我应该创建一个 @Input() 属性来传递 tours 数组和相对的 @Output() 并过滤 Observable 或在它们之间共享服务。
    • 请提供一个 StackBlitz 示例,它与您的示例非常接近,以便我可以分叉它
    • 谢谢,我解决了共享服务,现在可观察的来源是子组件中的控件,父组件只处理显示结果
    猜你喜欢
    • 2019-04-10
    • 2020-08-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-31
    • 2019-04-02
    • 2021-02-02
    相关资源
    最近更新 更多