Search code examples
angulartypescriptrxjsreactive-programming

How to use Observables within a method full of if-branching


Many times I faced this issue while trying to be more reactive, I am not able to find a clean way to do it, to make this method returns an Observable.

this is the example code:

public updateItemEligibility(item: Item): void
{
        this.updateCalculations(item);
        if (item.status == Status.Full)
        {
            this.markEligibleItem(item);
        }

        if (item.quantity > 0 && item.Stage == 1)
        {
           const info: ItemInfo =  this.getAdditionalInfoFromApi(); // will uses observable
           if (info.Staged)
           {
               this.updateStagedCalculations(item);
           }
        }

        if (item.quantity == 0 && item.Stage == 2)
        {
           const stagingInfo: StagingInfo =  this.getStaginInfoFromApi();
           item.eligible = this.allowStagedItems && item.amount > 0 && stagingInfo.Stages[item.stage].Completed == true;
        }
        this.updateTotals(item);
}

The problem here is calling the API only if a condition is satisfied.


Solution

  • If I understand your question right, you want a method that returns an Observable that notifies when the item is updated (if it has to be updated).

    If this is the case, then I would proceed as follows (the comments try to explain the logic)

     public updateItemEligibility(item: Item): Observable<Item> {
        // this initial part is untouched since I guess is all synchronous stuff
        this.updateCalculations(item);
        if (item.status == Status.Full) {
          this.markEligibleItem(item);
        }
        // here we start the ifs.
        if (item.quantity > 0 && item.Stage == 1) {
          // In the first case we want to return an Observable
          // that notifies after getAdditionalInfoFromApi has returned
          // we use the map operator to make this Oservable notify with the item as value
          // after performing all necessary things
          return this.getAdditionalInfoFromApi().pipe(
            map((info: ItemInfo) => {
              if (info.Staged) {
                this.updateStagedCalculations(item);
                this.updateTotals(item);
                return item;
              }
            })
          );
        }
        // here the second if
        if (item.quantity == 0 && item.Stage == 2) {
          // as we have done above, we return an Observable that notifies when getStaginInfoFromApi returns
          // (assuming that getStaginInfoFromApi returns an Oservable) and we use map
          // to make the Observable notify with item as value
          return this.getStaginInfoFromApi().pipe(
            map((stagingInfo: StagingInfo) => {
              item.eligible =
                this.allowStagedItems &&
                item.amount > 0 &&
                stagingInfo.Stages[item.stage].Completed == true;
              this.updateTotals(item);
              return item;
            })
          );
        }
        // if none of the conditions above is met, we return an
        // an Observable that notifies immediately with item as value
        // using the of function
        this.updateTotals(item);
        return of(item);
      }
    }