* ng对可观察的迭代。应该可以过滤onInput。怎么样?

时间:2017-09-27 09:01:18

标签: angular ionic2 rxjs observable

视图使用基于Observable:

的* ngFor列出条目

view.html

<ion-searchbar [(ngModel)]="filter" (ionInput)="filterMeds()"></ion-searchbar>
<ion-list>
  <ion-item *ngFor="let medicine of getMeds$() | async">
      {{medicine.name}}
  </ion-item>
</ion-list>

组件只通过getMeds $()函数中继一个observable:

component.ts

private _refreshOnInput$: Subject<any> = new Subject();


getMeds$(){
  return this.medsService.medsArray$;
}

服务本身只是将数组作为可观察对象返回:Observable<Medicine[]>

医学是由一些数字组成的普通物体。

现在,我的问题是:view.html添加了一个搜索栏。每当用户修改搜索条件时,都会调用filterMeds()函数:

filterMeds(){
  this._refreshOnInput$.next(true);
}

这是在blog post之后(cmd -f文本&#34;刷新按钮&#34;看看我尝试实施的内容)。

我理解我的* ngFor必须迭代一个observable,它会在应用一些过滤后合并原始this.medsService.medsArray$_refreshOnInput()

** component.ts尝试**

filteredMeds$: Observable<Medicine[]>

// Constructor

// An event is fired whenever the search input's updated
filteredMeds$ = this._refreshOnInput$.map( () =>
  this.medsService.medsArray$
    .map(meds =>
      meds.filter(med =>
        med.name.toLowerCase().indexOf(this.filter.toLowerCase()) > -1
      )
    )
);

this.meds$ = Observable.merge(this.medsService.medsArray$, filteredMeds$);

// Updating the getMeds$() method:
getMeds$(){
  return this.medsService.medsArray$;
}

我无法弄清楚如何创建有效的过滤流。当我直接将filteredMeds $ observable提供给* ngFor:

时,会发生同样的错误
ERROR Error: Error trying to diff '[object Object]'. Only arrays and iterables are allowed

2 个答案:

答案 0 :(得分:1)

我猜你应该以这种方式迭代(getMeds$() | async)

<ion-item *ngFor="let medicine of (getMeds$() | async)">

因为在您的示例中,您在 medicine 对象上使用异步管道,没有 getMeds $ 方法的结果。

但更好的方法是使用公共引用medsService(在组件中),你的ngFor循环应该是这样的:

<ion-item *ngFor="let medicine of (medsService.medsArray$ | async)">

因为你不应该在html中使用方法(作为ngFor循环或ngIf条件的参数)。在您的情况下,视图中的每个更改都将被称为getMeds $()方法,这对Observables来说完全没有必要。

答案 1 :(得分:0)

也许这不是最好的解决方案,但它有效。所以,请评论这种方法:

  private _refreshMeds: Subject<any> = new Subject();
  meds$: Observable<any>;
  filter: string = '';

  constructor(@Inject(MedsService) private medsService: MedsService) {

    let filtered$ = new Observable( obs => {
      this._refreshMeds.subscribe( () =>
        this.medsService.medsArray$.first().subscribe( medsArray => {

          const filteredMeds = medsArray.filter(med =>
            (this.filter.length === 0 ) ||
            (med.name.toLowerCase().indexOf(this.filter.toLowerCase()) > -1));
          obs.next(filteredMeds);
        })
      )
    });

    // Merging both the unfiltered (ie. at page load) or the filtered version
    this.meds$ = Observable.merge(this.medsService.medsArray$, filtered$);
  }

  // Called by the input's changed listener (ionic: ionInput)
  filterMeds(){
    this._refreshMeds.next(true);
  }