0

Note - I included a stackblitz link of this at the end.

I am having an issue with my code where I want a formcontrol to essentially be disabled if another formcontrol is currently populated. Example, if field A is populated then input fields B and C will be disabled. If field A is cleared out, then field B and C will re-enable. This occurs on all of the three fields in their respective order meaning if you populate B then A and C will be disabled, etc.

this.SearchForm.get('a').valueChanges
    .subscribe( ( value ) => {
      if ( value ) {
        this.SearchForm.get('b').disable();
        this.SearchForm.get('c').disable();
      } else {
        this.SearchForm.get('b').enable();
        this.SearchForm.get('c').enable();
      }
    });

If I only setup this on one field, this works great. However, if I change it to include setting up the other fields as followed:

this.SearchForm.get('a').valueChanges
    .subscribe( ( value ) => {
      if ( value ) {
        this.SearchForm.get('b').disable();
        this.SearchForm.get('c').disable();
      } else {
        this.SearchForm.get('b').enable();
        this.SearchForm.get('c').enable();
      }
    });

    this.SearchForm.get('b').valueChanges
    .subscribe( ( value ) => {
      if ( value ) {
        this.SearchForm.get('a').disable();
        this.SearchForm.get('c').disable();
      } else {
        this.SearchForm.get('a').enable();
        this.SearchForm.get('c').enable();
      }
    });

    this.SearchForm.get('c').valueChanges
    .subscribe( ( value ) => {
      if ( value ) {
        this.SearchForm.get('a').disable();
        this.SearchForm.get('b').disable();
      } else {
        this.SearchForm.get('a').enable();
        this.SearchForm.get('b').enable();
      }
    });

I get the "Maximum call stack size exceeded" error. Maybe there is a better way of doing this with reactive forms, but I haven't come across anything yet. Part of the reason I took this approach is because once the field is empty it will re-enable the other fields easily with less code.

Link of Stackblitz If you comment out the valueChanges of b and c and just have one, you can see the kind of behavior I am looking for, but if you add even one additional valuechanges it gets the error.

1
  • 1
    Probably because enabling/disabling other formControl triggers its change listener Commented Nov 12, 2019 at 17:27

2 Answers 2

1

There is an emitEvent option for the disable() / enable() method:

disable(opts: { onlySelf?: boolean; emitEvent?: boolean; } = {}): void
enable(opts: { onlySelf?: boolean; emitEvent?: boolean; } = {}): void

https://angular.io/api/forms/AbstractControl

Try passing in { emitEvent: false }

const disableEnableOptions = {emitEvent: false };
this.SearchForm.get('a').valueChanges
    .subscribe( ( value ) => {
      if ( value ) {
        this.SearchForm.get('b').disable(disableEnableOptions);
        this.SearchForm.get('c').disable(disableEnableOptions);
      } else {
        this.SearchForm.get('b').enable(disableEnableOptions);
        this.SearchForm.get('c').enable(disableEnableOptions);
      }
    });

This should stop your changes from triggering your other subscribers. You should be able to implement this throughout the rest of your code.

Here is my fork of your stackblitz: https://stackblitz.com/edit/angular-w5r29c

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you for your help. I see from the documentation it says the following: emitEvent: When true or not supplied (the default), both the statusChanges and valueChanges observables emit events with the latest status and value when the control is disabled. When false, no events are emitted. I'm not really clear by what it means here and why this addresses the issue?
The framework is wired to emit an event to both statusChanges and valueChanges observables when you call disable or enable(). When you set emitEvent to false, it prevents this from happening. It fixes your issue because you subscribe to valueChanges for "a", "b", and "c".
0

When you call value change "a", you call another value change and so forth, until you hit the call stack limit.

Basically complete form is mapped on a model, so whenever you enable/disable any control, the form model's property changes. And because the model is changing so valueChanges event will be triggered.

If you use new version angular, you probably can use

this.form.get('b').setValue(newValue, {onlySelf: true, emitEvent: false});

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.