如何处理在Angular中异步启动的属性?

时间:2018-05-01 14:05:50

标签: angular typescript firebase rxjs google-cloud-firestore

我试图从角度的服务中获取AngularFirestoreCollection。 AngularFirestoreCollection在可观察订阅中异步初始化。当我尝试从组件中获取集合时,我收到错误,因为它未定义。

以下是我服务的代码:

collapse

这是我的组件的代码:

fokosCollection: AngularFirestoreCollection<Foko>;
myFokos: Observable<Foko[]>;

constructor(auth: AuthService, public afs: AngularFirestore) {

  this.myFokos = auth.user$.switchMap(user => {
    if (user) {
      this.fokosCollection = afs.collection<Foko>('users/' + user.uid + '/fokos');
      return this.fokosCollection.valueChanges();
    }
  });

}

我尝试创建一个在初始化Collection时通知组件的Subject。当我直接导航到此组件时,这有效。但是,如果我从另一个组件导航到此组件,则从不调用主题订阅(因为主题发出集合时订阅不存在)。

以下是我的尝试:

 this.myListService.fokosCollection.doc(codeInput).valueChanges().take(1).subscribe(foko => {
   getData(foko)
 });

我将组件的代码更改为:

fokosCollection: AngularFirestoreCollection<Foko>;
fokosCollectionSubject = new Subject<AngularFirestoreCollection<Foko>>();
myFokos: Observable<Foko[]>;

constructor(auth: AuthService, public afs: AngularFirestore) {

  this.myFokos = auth.user$.switchMap(user => {
    if (user) {
      this.fokosCollection = afs.collection<Foko>('users/' + user.uid + '/fokos');
      this.fokosCollectionSubject.next(this.fokosCollection);
      ...

我可以尝试获取Collection,如果它抛出错误,请订阅Subject。但是,我认为这不是好的代码。那么,在Angular中使用异步数据进行去除的最佳做法是什么?

1 个答案:

答案 0 :(得分:1)

在您的switchMap中,如果用户是假的,则您不会返回值。你应该归还一些东西。使用filter运算符可以防止出现这种情况。

由于您想知道何时初始化fokosCollection,我建议您将其作为可观察对象公开。

fokosCollection: Observable<AngularFirestoreCollection<Foko>>;
myFokos: Observable<Foko[]>;

constructor(auth: AuthService, public afs: AngularFirestore) {
  this.fokosCollection = auth.user$
    .filter(x => x != null)
    .map(user => afs.collection<Foko>('users/' + user.uid + '/fokos'))
    .shareReplay(1);
  this.myFokos = this.fokosCollection.switchMap(x => x.valueChanges());
}

我添加了shareReplay(1)来共享单个基础订阅,并将最后一个值重播给新订阅者。你可能会或可能不想在你的场景中使用它,但我发现在暴露可能有多个订阅的observable时我通常会想要它。

然后在你的组件中:

this.myListService.fokosCollection.switchMap(x => x.doc(codeInput).valueChanges()).take(1).subscribe(foko => {
   getData(foko)
 });