AngularFire2 FirebaseListObservable跨多个(路由)组件

时间:2016-12-29 20:00:20

标签: angular typescript firebase angularfire2

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

过滤组件

<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的摘录,用于处理此问题。

Firebase服务处理程序(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()方法已运行并创建了新版本的列表。

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

所以我不知道这是否对任何人都有意义,是否有一个相当简单的解决方案,或者我是否已经陷入了一个兔子洞,需要重新思考。

感谢任何帮助!!

谢谢

1 个答案:

答案 0 :(得分:2)

如果要对过滤器使用observable,则可以组合一个将最新数据库列表与最新过滤器组合在一起的observable。

过滤器具有初始值,因此您可以使用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;
  }

然后,您只需要一个组合的可观察对象。所以你可以在构造函数中创建它。