Search code examples
angularrxjsmergemap

mergeMap not returning data when inner observable is empty/ api returns no data


I am trying to merge three observables and when the inner observable does not have any data, the mergeMap is not returning any data. I want to be able to continue the process even if one of the inner observable is empty. How do I handle this situation? Here is my code:

    ngOnInit() {
        this.accountStatusSub = this.accountService.accountNumberChange$.subscribe(
          accNumber => 
              {this.accountNumber = accNumber;


            var obs = this.accountService.getAccountDetails(this.accountNumber)
                  .pipe(mergeMap(accountData =>
                    this.accountService.getBill(accountData.account[0].accountNumber)
                      .pipe(mergeMap(billData =>
                        this.accountService.getPayment(accountData.account[0].accountNumber)
                          .pipe(map(paymentData => ({
                            address1: accountData.account[0].address1,
                            address2: accountData.account[0].address2,
                            city: accountData.account[0].city,
                            state: accountData.account[0].state,
                            zip: accountData.account[0].zip,
                            amountDue: billData.bill[0].amountDue,
                            dueDate: billData.bill[0].dueDate,
                            lastPaymentAmount: paymentData.payment[0].paymentAmount,
                            lastPaymentDate: paymentData.payment[0].paymentDate
                          })

                          ))
                      ))
                  ))


                obs.subscribe(combinedAccountData => {
                  console.log('MergeMap:', combinedAccountData)
                })

              })
          }

combinedAccountData is empty when either billData or paymentData is empty. Is there a better way to write the above code? I am new to angular and rxjs. Thanks.


Solution

  • UPDATED

    the desired bahevior was achieved by

    ngOnInit() {
      this.accountStatusSub = this.accountService.accountNumberChange$.pipe(
        tap(accNumber => console.log(accNumber)),
        mergeMap(accNumber => {
          this.accountNumber = accNumber;
          const getAccount = this.accountService.getAccountDetails(accNumber);
          const getBill = this.accountService.getBill(accNumber);
          const getPayment = this.accountService.getPayment(accNumber);
          return forkJoin(getAccount, getBill, getPayment);
        })
       ).subscribe();
    }
    

    ORIGINAL

    if they can return empty data you can return an empty object and spread it. Depends on structure you want to get.

    ngOnInit() {
        this.accountStatusSub = this.accountService.accountNumberChange$.pipe(
            switchMap(accNumber =>
                this.accountService.getAccountDetails(accNumber),
            ),
            switchMap(accountData => combineLatest([
                of(accountData),
                this.accountService.getBill(accountData.account[0].accountNumber),
                this.accountService.getPayment(accountData.account[0].accountNumber),
            ])),
            map(([accountData, billData, paymentData]) => ({
                address1: accountData.account[0].address1,
                address2: accountData.account[0].address2,
                city: accountData.account[0].city,
                state: accountData.account[0].state,
                zip: accountData.account[0].zip,
                billData,
                ...( billData?.bill && billData.bill[0] ? {
                  amountDue: billData.bill[0].amountDue,
                  dueDate: billData.bill[0].dueDate,
                } : {}),
                paymentData,
                ...( paymentData?.payment && paymentData.payment[0] ? {
                  lastPaymentAmount: paymentData.payment[0].paymentAmount,
                  lastPaymentDate: paymentData.payment[0].paymentDate
                } : {}),
            }))).subscribe(combinedAccountData => {
                console.log('MergeMap:', combinedAccountData)
            });
    }