Search code examples
angularrxjsangularfire2

AngularFire collection: Update/replace query path with a new path


I have a service that has an AngularFirestore.collection Observable.

...
export class AppFirestoreService {
  public rootCategories$: Observable<Category[]>;

  constructor(private afs: AngularFirestore) {
    this.rootCategories$ = this.afs.collection<Category>(`categories`).snapshotChanges()
    .pip(
      ...
    );
  }
}

The problem is that the rootCategories$ is subscribed in several components, and the path I need update to another one.

So I thought of replacing the rootCategories variable with a new Observable, but I'm not sure if the old Observable will be cleared of the memory. Is there is a way to make the path as a variable without create another Observable and leaving the old one (or its subscription) existing in memory. Thanks

Can you please guide me to correct way to solve this problem.

Editing to clarify: How to change the current Observable rootCategories$ with new path, and make old subscription notified with the new emitted value?


Solution

  • I found a solution, unless someone points out it has some drawbacks on it.

    The combination of BehaviorSubject and mergeMap, solved my problem. The path is emmitted and controlled from a BehaviorSubject and the AngularFirestore.collection is returned with the new path:

    import { Injectable } from '@angular/core';
    import { AngularFirestore } from '@angular/fire/firestore'
    import { Observable, BehaviorSubject } from 'rxjs';
    import { mergeMap } from 'rxjs/operators';
    ...
    @Injectable(...)
    export class AppFirestoreService {
      public rootCategories$: Observable<CategoryId[]>;
      private pathBS = new BehaviorSubject<string>('categories');
    
      constructor(private afs: AngularFirestore) {
        this.rootCategories$ = this.pathBS.asObservable().pipe(
          mergeMap(path => {
            return this.afs.collection<Category>(path).snapshotChanges()...
          })
        );
      }
    
      setNewPath(path: string) {
        this.pathBS.next(path);
      }
    }