简体   繁体   English

如何在客户端过滤FirebaseListObservable?

[英]How to filter FirebaseListObservable on client side?

I am using AngularFire2 within an Angular web app. 我在Angular Web应用程序中使用AngularFire2。 Due to the query limitations of Firebase, I can't form a query that delivers exactly the data I need (At least not without making major changes to my schema). 由于Firebase的查询限制,我无法形成一个完全提供所需数据的查询(至少在没有对我的架构进行重大更改的情况下)。

So I want to apply an additional client-side filter criteria within javascript (typescript). 所以我想在javascript(typescript)中应用额外的客户端过滤条件。 How do I do this? 我该怎么做呢? Can I somehow add a filter function to the observable? 我可以以某种方式向observable添加过滤函数吗? Below is a fragment that illustrates what I'm doing. 下面是一个片段,说明了我在做什么。

In the HTML Template for the component, I have something like this below. 在组件的HTML模板中,我有类似下面的内容。 The "jobs" variable in the html fragment is a FirebaseListObservable. html片段中的“jobs”变量是FirebaseListObservable。

<tr *ngFor="let job of jobs | async"> 
  .. fill in the table rows

The component code looks like this: 组件代码如下所示:

   // in the member declaration of the class
   jobs : FirebaseListObservable<Job[]>;

   ...
   // Notice in ngOnInit(), I'm filtering the jobs list using the the
   // Firebase criteria. But I want to filter on an additional field. 
   // Firebase allows only single field criteria, so I'm looking for 
   // a way to apply an additional client-side filter to jobs to eliminate
   // some additional records. 

   ngOnInit(){
      this.jobs = this.af.database.list("/jobs/", {query: {orderByChild : "companyKey", equalTo:someKey}})
   }

Is there a way to apply a filter component on "this.jobs" so that I can apply a local (client-side) filter? 有没有办法在“this.jobs”上应用过滤器组件,以便我可以应用本地(客户端)过滤器?

I ran into the same issue. 我遇到了同样的问题。 The missing piece was to filter the array itself ( Job[] ), and not the Observable wrapper around it ( FirebaseListObservable<Job[]> ). 缺少的部分是过滤数组本身( Job[] ),而不是它周围的Observable包装器( FirebaseListObservable<Job[]> )。

Was able to do this using the RxJS operator map . 能够使用RxJS运算符map执行此操作。

import {Observable} from 'rxjs/Observable';
import 'rxjs/add/operator/map'

...

@Component({
  ...
})
export class JobComponent {

  ...

  getJobsLessThanPrice(price: number): Observable<Job[]> {
    return this.af.database.list('jobs', {query: {...}})
      .map(_jobs => _jobs.filter(job => job.price > price));

  }
}

If job.price > price returns true, then it's included. 如果job.price > price返回true,则包含它。

Also noticed your jobs property was of type FirebaseListObservable<Job> , I would have thought the observable type should be Job[] vs Job . 还注意到你的jobs属性是FirebaseListObservable<Job>类型,我原本认为可观察类型应该是Job[] vs Job

I haven't found a way to really filter on the observable, but I have found a workaround for some cases. 我还没有找到真正过滤observable的方法,但我找到了一些针对某些情况的解决方法。 One can pseudo-filter in the element with *ngFor. 可以使用* ngFor在元素中进行伪过滤。 So my example becomes 所以我的榜样变成了

<tr *ngFor="let job of jobs | async" [hidden]="filter(job)"> 
  .. fill in the table rows

Add we add the filter() method to our component code: 添加我们将filter()方法添加到我们的组件代码:

// in the member declaration of the class
   jobs : FirebaseListObservable<Job[]>;

   ...

   ngOnInit(){
      this.jobs = this.af.database.list("/jobs/", {query: {orderByChild : "companyKey", equalTo:someKey}})
   }

   filter(job : Job) : boolean{
     // Return true if don't want this job in the results.
     // e.g. lets filter jobs with price < 25;
     if (job.price < 25){
       return true;
     }
     return false; 
  }

I'm still looking for a way to really filter on the observable, but for the meantime, this workaround is usable. 我仍然在寻找一种真正过滤observable的方法,但与此同时,这种解决方法是可用的。

you can write your own pipe (similar to Filter on Angular 1.X) 你可以编写自己的管道 (类似于Angular 1.X上的Filter

import {Pipe, PipeTransform} from '@angular/core';
import * as _ from 'lodash';

@Pipe({
  name: 'search'
})
export class SearchPipe implements PipeTransform {

 transform(value: any, args?: any): any {

  if (args) {
    return _.filter(value, d => _.find(_.valuesIn(d), v => 
        _.toLower(v).indexOf(_.toLower(args)) !== -1));
  }

 return value;
 }
 }   

then, use this Pipe in component's template: 然后,在组件的模板中使用此管道:

<input [(ngModel)]="term"> 
<li *ngFor="let item of items | async | search:term">{{item}}</li>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM