Search code examples
javascriptrxjsobservablesubscription

How do I build validation into an Observable, and conditionally emit?


An excerpt from an Angular class:

optionalString = new BehaviorSubject<string | undefined>(undefined);
  
// used to show that there may be multiple conditions involved
alwaysTrueFlag = new BehaviorSubject<boolean>(true);
                                

ngOnInit(): void {
  combineLatest([
    this.optionalString.pipe(skip(1)),
    this.alwaysTrueFlag
  ]).pipe(tap(([str, flag]) => {
    // I hope `str` is a valid number, but it's getting
    // "forwarded" to `subscribe` anyway...
  })).subscribe(result => explodeIfNotNumber(result));
}

onKeyPress() {
  this.optionalString.next(prompt('please enter a number'));
}

Since I can't control what happens in subscribe, I'd like to avoid its getting triggered – unless the value obtained from the observable is valid (in this case a valid number).

I could control the source, i.e. this onKeyPress here, and check if the entered string may safely be converted to a number, but I can't guarantee that every user of optionalString is going to follow this, so I want to build validation into the observable itself.

If I'm going about this the wrong way, please tell me the conventional way of doing it. I haven't been able to find anything useful by googling. Thanks.


Solution

  • You could filter out non-numeric values.

    import { filter, map, skip, tap } from 'rxjs/operators';
    ..
    ...
    ngOnInit(): void {
      combineLatest([
        this.optionalString.pipe(skip(1)),
        this.alwaysTrueFlag
      ]).pipe(
        map(([str, flag]) => ({str, flag})), // Added to simplify the code in the next steps
        filter(({str}) => !isNaN(Number(str))), // Filter the values and emit only valid numbers
        tap(({str, flag}) => {
          // Only run for valid numbers & numeric values
        })
      ).subscribe(({str}) => explodeIfNotNumber(str));
    }
    

    Since filter is added, subscribe would only be triggered if the input is numeric