3

I have created a StackBlitz example of my problem.

I have a FormService that builds a form, which is obtained by the component in the initForm() method:-

public getForm() {
  return this.fb.group({
    cb1: this.fb.control(false),
    cb2: this.fb.control(false),
    inputBox: this.fb.control({value: '', disabled: true}, Validators.required)
  });
}

I need to disable the input text box if none of the checkboxes is selected. Which brings me to do something like this :-

if(!this.cb1.value && !this.cb2.value) {
  this.isCheckboxSelectionInvalid = true;
  this.inputBox.disable();
} else {
  this.isCheckboxSelectionInvalid = false;
  this.inputBox.enable();
}

This works for all default scenarios - however there is a problem. When I call resetForm() (provided the input is enabled by checking one of the checkboxes) which basically calls the same method of initForm(), the input stays enabled. This is even after I call the method that validates checkbox selection and disables the input in the initForm() method.

For sanity, I logged the value of the input's disabled property - which logs true.

Why is it that the input doesn't get disabled then? Any help would be very appreciated, this is a problem at work.

2 Answers 2

1

The problem you are facing is related to an angular bug, you can find more info here.

There are some workarounds that worked for me:

  1. Call disable function inside setTimeout.
validateCheckboxSelectionAndChangeInputState() {
  if (!this.cb1.value && !this.cb2.value) {
     this.isCheckboxSelectionInvalid = true;
     setTimeout(() => {
        this.inputBox.disable();
     }, 0);
  } else {
     this.isCheckboxSelectionInvalid = false;
     this.inputBox.enable();
  }
}
  1. Set directly the disabled attribute:
<input type="text" [attr.disabled]="form.controls['inputBox'].disabled" formControlName="inputBox" />
  1. Call detectChanges before calling enable/disable functions.
validateCheckboxSelectionAndChangeInputState() {
  this.ref.detectChanges();
  if (!this.cb1.value && !this.cb2.value) {
    this.isCheckboxSelectionInvalid = true;
    this.inputBox.disable();
  } else {
      this.isCheckboxSelectionInvalid = false;
      this.inputBox.enable();
  }
}


Suggestions not related to the problem:


With the idea of ​​enabling or disabling the control, you can subscribe to form valueChanges:

  initForm() {
    this.form = this.formService.getForm();
    this.cb1 = this.form.get("cb1");
    this.cb2 = this.form.get("cb2");
    this.inputBox = this.form.get("inputBox");
    this.form.valueChanges.subscribe(
      this.validateCheckboxSelectionAndChangeInputState.bind(this)
    );     
  }

  validateCheckboxSelectionAndChangeInputState(controls) {
    if (this.inputBox.disabled && controls.cb1 && controls.cb2) {
      this.inputBox.enable();
    } 
    if(this.inputBox.enabled && !controls.cb1 && !controls.cb) {
       setTimeout(() => {
          this.inputBox.disable();
       }, 0);
    } 
  }

  toggleCb1() {
    this.cb1.setValue(!this.cb1.value);
  }

  toggleCb2() {
    this.cb2.setValue(!this.cb2.value);
  }

  resetForm() {
    this.initForm();
  }

Also you can [disabled] the button using form.valid, and using the Validators.requiredTrue:

html

 <button [disabled]="!form.valid" (click)="submitForm()">
    Submit
  </button>

ts

public getForm() {
    return this.fb.group({
      cb1: this.fb.control(false, [Validators.requiredTrue]),
      cb2: this.fb.control(false, [Validators.requiredTrue]),
      inputBox: this.fb.control(
        { value: "", disabled: true },
        [Validators.required]
      )
    });
  }

See https://stackblitz.com/edit/angular-6-reactive-form-disable-jn4cf8?file=src%2Fapp%2Fapp.component.ts

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

6 Comments

This still doesn't work. Try this - enable the inputBox by toggling ON both the checkboxes. Type something in the inputBox, and then click on Reset button. Expectation - Since both are false, The inputBox should be disabled. Reality - inputBox is enabled, we can type into it.
This is now seeming more and more like a bug in the way it is implemented in Angular itself.
Yes, I see the input is not disabled, I added a setTimeout(() => { this.inputBox.disable(); }, 0); and it works, very weird
it looks like it's a bug, github.com/angular/angular/issues/22556
Hey, nice find! I tried to find it first but to no avail. The setTimeout hack works though! Accepting this answer.
|
0

How about not making another form instance, and actually resetting existing form?

  resetForm() {
    this.form.reset({
      cb1: false,
      cb2: false
    });
    this.validateCheckboxSelectionAndChangeInputState();
  }

https://stackblitz.com/edit/angular-6-reactive-form-disable-pefhmc

2 Comments

Doesn't work. Tried that as well. That is because on calling reset, form values are set to null. This does not disable the input.
Edit. But you should consider adding FormGroup validation.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.