Search code examples
angularrxjsobservableangular-observable

Function which returns RxJs boolean observable - emit single value and complete


I have several functions in an angular project which return a boolean observable. Some of these functions could simply return an immediate result, but could also contain nested observables that open confirmation dialogs or fetch data. What I'm trying to do is reduce the amount of code with repeated .next(value) followed by complete() code.

Is there a way to emit a value and complete the observable (so that we don't have to unsubscribe), say like subscriber.complete(value), or is there a better way to accomplish this with different rxjs operators?

checkClientState = (state: ClientState, assistanceType: AssistanceType) => {
  return new Observable<boolean>((subscriber) => {
    if (state.isValid) {
      subscriber.next(true)
      subscriber.complete();
    }
    else {
      this.dialogService.confirm('Application Required', 'This Application is currently closed. Would you like to create a new Application?')
        .subscribe((confirmed) => {
          if (confirmed)
            this.applicationService.openNewApplication(this.store, assistanceType)
              .subscribe((result) => {
                subscriber.next(result);
                subscriber.complete();
              })
          else {
            subscriber.next(false)
            subscriber.complete();
          }
        })
    }
    });
}

I have tried using rxjs of(value) but it comes back to having to repeat subscriber.complete() for the observable.


Solution

  • We can use switchMap and of to simulate the sequence, if state is value, just return of(true) else use switchMap to execute the rest of the sequence.

    import './style.css';
    
    import { rx, of, map, takeWhile } from 'rxjs';
    import { delay, switchMap, take } from 'rxjs/operators';
    
    function checkClientState(state: any, assistanceType: any) {
      return state.isValid
        ? of(true)
        : of(true).pipe(
            switchMap(() => {
              return this.dialogService.confirm('Application Required', 'This Application is currently closed. Would you like to create a new Application?')
              // return of(true) // simulate `this.dialogService.confirm` try toggling the boolean
              //   .pipe(delay(2000)) // simulate `this.dialogService.confirm` try toggling the boolean
                .pipe(take(1), map((confirmed: boolean) => confirmed || false));
            })
          );
    }
    
    checkClientState({ isValid: true }, {}).subscribe({
      next: (data) => console.log('next', data),
      error: (data) => console.log('error', data),
      complete: () => console.log('complete'),
    });
    

    Stackblitz Demo