How to handle multiple observable with NGXS firestore in Angular 10

Hello here I will explain how to handle the multiple observable with NGXS firestore, I was working on an angular firebase project with NGXS and I faced a challenge to call 2 queries and return the result from both queries.

What is Observable

Observables are are used to manage the async requests, like callbacks and promises are used for handling async requests. Observables are a part of the RXJS library.

My problem:

Fetch the data from the employee and employee_details collection.

employee collection fields are: full_name, email employee_details collection fields are: first_name, last_name, address, city, state, company_name, department

to handle this challenge I used combineLatest

What is combineLatest

combineLatest is an operator of the RXJS, it is used when you have multiple long-lived observable i.e. the observable depends on each other and you need to return the both observable once both complete.

Example:

// RxJS v6 
import { timer, combineLatest } from 'rxjs';

// timerOne emits first value at 1s, then once every 4s
const timerOne$ = timer(1000, 4000);
// timerTwo emits first value at 2s, then once every 4s
const timerTwo$ = timer(2000, 4000);
// timerThree emits first value at 3s, then once every 4s
const timerThree$ = timer(3000, 4000);

// when one timer emits, emit the latest values from each timer as an array
combineLatest(timerOne$, timerTwo$, timerThree$).subscribe(
  ([timerValOne, timerValTwo, timerValThree]) => {
    /*
      Example:
    timerThree first tick: 'Timer One Latest: 0, Timer Two Latest: 0, Timer Three Latest: 0
    timerOne second tick: 'Timer One Latest: 1, Timer Two Latest: 0, Timer Three Latest: 0
    timerTwo second tick: 'Timer One Latest: 1, Timer Two Latest: 1, Timer Three Latest: 0
  */
    console.log(
      `Timer One Latest: ${timerValOne},
     Timer Two Latest: ${timerValTwo},
     Timer Three Latest: ${timerValThree}`
    );
  }
);

Multiple observable in NGXS Firestore

Here ngxsFirestoreConnect is used to


// with different observable
let employee = this.employee_firestore.doc$(userId);
let employee_details = this.employee_details_firestore.doc$(userId);

return combineLatest(employee, employee_details); 


// with inline observable
return combineLatest(this.employee_firestore.doc$(userId), this.employee_details_firestore.doc$(userId));

Complete code of NGXS firstore for multiple observable

import { Action, NgxsOnInit, Select, Selector, State, StateContext, Store } from '@ngxs/store';
import { Injectable } from '@angular/core';

import { combineLatest, Observable } from 'rxjs';
import { filter, flatMap, map } from 'rxjs/operators';
import { Emitted, NgxsFirestoreConnect, StreamEmitted } from '@ngxs-labs/firestore-plugin';
import { patch } from '@ngxs/store/operators';
import { AuthModel } from './auth.state';
import { EmployeeActions } from './actions/employee.actions';
import { EmployeeFirestore } from './firestore/employee.firestore';
import { EmployeeDetailsFirestore } from './firestore/employee-details.firestore';


export interface EmployeeCollection {
  full_name: string;
  email: string;
}

export interface EmployeeDetails {
  city: string;
  address: string;
  last_name: string;
  first_name: string;
}


export interface IEmployeeStateModel {
  employee: EmployeeCollection;
  employeeDetails: EmployeeDetails;
}

@State<IEmployeeStateModel>({
  name: 'employee',
  defaults: {
    employee: null,
    employeeDetails: null,
  },
})
@Injectable()
export class EmployeeState implements NgxsOnInit {
  @Select((a: any) => a.authData) authUser$: Observable<AuthModel>; // ead data from the auth state

  @Selector()
  public static getEmployee(state: IEmployeeStateModel): EmployeeCollection {
    return state.employee;
  }

  ngxsOnInit(ctx: any) {
    this.ngxsFirestoreConnect.connect(EmployeeActions.Get, {
      to: () =>
        this.authUser$.pipe(
          filter((user: any) => user?.authData?.uid !== undefined),
          map((user) => user.authData.uid),
          flatMap((userId) => {
            return combineLatest(this.employeeFS.doc$(userId), this.employeeDetailsFS.doc$(userId));
          }),
        ),
    });

    // start listening to the auth uid
    ctx.dispatch(new EmployeeActions.Get());
  }

  constructor(
    private employeeFS: EmployeeFirestore,
    private employeeDetailsFS: EmployeeDetailsFirestore,
    private ngxsFirestoreConnect: NgxsFirestoreConnect,
  ) {}

  @Action(StreamEmitted(EmployeeActions.Get))
  get(
    ctx: StateContext<IEmployeeStateModel>,
    { payload }: Emitted<EmployeeActions.Get, EmployeeCollection>,
  ) {
    ctx.setState(
      patch({
        employee: payload[0] ? payload[0] : null,
        employeeDetails: payload[1] ? payload[1] : null,
      }),
    );
  }
}

conclusion

We learnt how to handle the multiple observable with NGXS firestore. please feel free to contact if you need any help. Thanks


Related blog of angular