2016-12-29 43 views
0

我正在尝试为Angular2/Firebase/AngularFire为我们的帆船俱乐部构建一个社交平台。第一个模块是允许用户通过几个标准(过滤器)搜索俱乐部会员,最多可达10个左右。 这本身就意味着我必须搜索大量技术来克服Firebase中缺乏查询功能。 我创建了一个组件来管理过滤器,使用子路由组件来保存已成功过滤的成员列表,然后最终生成一个单击处理程序,然后路由到成员配置文件本身。 过滤器组件如下所示: HTML模板包含用于所有过滤器选择的多个收音机,例如:性别。点击后,会触发onFilter方法。跨多个(路由)组件的AngularFire2 FirebaseListObservable

过滤器部件

<div class="radio"> 
    <label> 
    <input type="radio" name="genderRadios" id="genderRadioM" value="genderMale" (click)="onFilter('crewGender', 'M')"> 
      Male 
    </label> 
</div> 

这是则onFilter方法

constructor(private crewService: CrewService) {} 

onFilter(myType, myParam) { 
    this.crewFilter = this.crewService.updateFilter(myType, myParam); 
} 

这使得一个调用“crewService”服务来更新滤波器阵列用新值。

这是处理此问题的crewService的摘录。

火力地堡服务处理器(CrewService)

updateFilter(myType, myParam){ 
    this.crewFilter[myType] = myParam; 
    return this.crewFilter; 
} 

你可以看到crewFilter阵列只会持有密钥的列表:所有滤镜值对。然后CrewService服务实现一个方法,该方法使用过滤器数组并将其用作针对我调用的AngularFire列表的过滤器,并最终将其生成为FireBaseListObservable。

@Injectable() 
export class CrewService { 
    private crewFilter:any[] = []; 
    crews:FirebaseListObservable<any[]>; 

    constructor(private af: AngularFire) {} 

    getCrews() { 
    this.crews = this.af.database.list('/crew').map(items => { 
    const filtered = items.filter(item => { 
    let match:boolean = true; 
    for (let i in this.crewFilter) { 
     if(this.crewFilter[i] !== 'A') { 
     if (item[i] !== this.crewFilter[i]) match = false; 
     } 
    } 
    return match; 
    }); 
    return filtered; 
}) as FirebaseListObservable<any[]>; 

到目前为止。太好了。根据所有过滤器(忽略A)成功过滤Firebase列表。然后在组件模板中显示列表,我使用标准的ngFor循环来解析它们。

列表组件

<div *ngFor="let crew of crews | async; let i = index" class="crewsummary row"> 

因此,TS文件包含:

constructor(private crewService: CrewService) { } 

ngOnInit() { 
    this.crews = this.crewService.getCrews(); 
    this.crewFilter = this.crewService.getFilter(); 
} 

所以我叫crewService来填充地方“船员的对象。

此组件我也创建按钮以取消过滤器内部(A指所有,因此点击按钮设置过滤器,以“A”,然后在过滤器中被忽略):

<a *ngIf="crewFilter['crewGender'] == 'M'" class="btn btn-primary" (click)="onFilter('crewGender', 'A')">gender: <b>Male</b> <i class="fa fa-fw fa-times"></i></a> 
<a *ngIf="crewFilter['crewGender'] == 'F'" class="btn btn-primary" (click)="onFilter('crewGender', 'A')">gender: <b>Female</b> <i class="fa fa-fw fa-times"></i></a> 

再次与TS:

onFilter(myType, myParam) { 
    this.crewFilter = this.crewService.updateFilter(myType, myParam); 
    this.crews = this.crewService.getCrews(); 
} 

因为成员列表是由该组件产生的,当我运行onFilter()列表组件内部,它正确地刷新列表,我得到正确的结果。

这就是乐趣开始的地方!

当我在过滤器组件的第一个地方应用过滤器时,我可以让服务重新运行crewService.getCrews()来应用过滤器,但它不会被填充到列表组件。

我一直无法找到一种方法来强制列表组件知道CrewService.getCrews()方法已经运行并创建了新版本的列表。

许多小时的搜索和尝试与观察和订阅等相关的事情都失败了,我不能让列表组件成功地“订阅”我在应用过滤器时对工作组对象的更改。 (请注意,数据库本身所做的更改已成功传播)

所以我不知道这是否对任何人都有意义,以及是否存在相当简单的解决方案,或者我是否放弃了兔子洞并需要再想一想。

感谢任何帮助!

谢谢

托尼

回答

2

如果你使用的观察到的,过滤器,你可以组成一个可观察的,它结合了最新的过滤器最新的数据库列表。

过滤器具有一个初始值,所以你可以使用BehaviorSubject,像这样:

import { BehaviorSubject } from 'rxjs/BehaviorSubject'; 
import 'rxjs/add/operator/combineLatest'; 

@Injectable() 
export class CrewService { 

    private crewFilter:any[] = []; 
    private crewFilterSubject = new BehaviorSubject(this.crewFilter); 

    constructor(private af: AngularFire) { 
    this.crews = this.af.database 
     .list('/crew') 
     .combineLatest(this.crewFilterSubject, (items, filter) => { 
     const filtered = items.filter(item => { 
      let match:boolean = true; 
      for (let i in filter) { 
      if(filter[i] !== 'A') { 
       if (item[i] !== filter[i]) match = false; 
      } 
      } 
      return match; 
     }); 
     return filtered; 
     }) as FirebaseListObservable<any[]>; 
    } 

    updateFilter(myType, myParam){ 
    this.crewFilter[myType] = myParam; 
    this.crewFilterSubject.next(this.crewFilter); 
    return this.crewFilter; 
    } 

    getCrews() { 
    return this.crews; 
    } 

你会那么只需要一个单一的,由可观察的。所以你可以在构造函数中创建它。

+0

天才!真的非常感谢你 !完美的作品。移动到构造函数也感觉好多了。已经标记为接受,你为我节省了很多时间和痛苦,再次感谢你! –

相关问题