Search code examples
angularrxjsobservablebehaviorsubject

How to chain subscription on BehaviorSubject<boolean>?


I have an Angular app which shows and hides an input field depending on the contents of another input field. Now I need to do some auto formatations on the second field when the user types something into it. But the field is hidden when the component loads, so I need to check the values of the first field to check if the second should be shown and then, when it is visible subscribe to its valueChanges.

My code looks like this:

export class MyInputComponent implements AfterViewInit {
  private subscription = Subscription.EMPTY;

  @ViewChild('firstInput', { read: NgControl }}
  public firstInput: NgControl;

  @ViewChild('secondInput', { read: NgControl }}
  public secondInput: NgControl;

  public isSecondInputVisible = new BehaviorSubject<boolean>(false);

  public ngAfterViewInit() {
    this.firstInput.valuesChanges!.subscribe((first) => {
      this.isSecondInputVisible.next(first.length > 4);
    });

    this.isSecondInputVisible.subscribe((isVisible) => {
      if (isVisible) {
        this.subscription = this.secondInput.valueChanges!.subscribe((value) => {
          // do something...
        });
      } else {
        this.subscription.unsubscribe();
      }
    });
  }
}

I was wondering if there is a way to chain the subscriptions, I won't have too much indentation and nesting in the code. I thought this may be possible using pipe but I have not yet found a way.

Is there a way to optimize the subscription part?


Solution

  • You can use concatMap and inside it return empty() in case the field is invisible.

    this.isSecondInputVisible
      .pipe(
        concatMap(isVisible => isVisible
          ? this.secondInput.valueChanges!
          : empty()
        )
      )
      .subscribe(valueChanged => /* do something...*/)