2016-12-29 46 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

天才!真的非常感謝你 !完美的作品。移動到構造函數也感覺好多了。已經標記爲接受,你爲我節省了很多時間和痛苦,再次感謝你! –

相關問題