What's the best way to temporarily disable every field of an Angular form?

84 Views Asked by At

I know how to do that in two ways (demo of both here). The two are applicable both to template-driven and reactive forms because both of them rely on the FormGroup API.

formGroup.enable() and formGroup.disable()

<form ngForm>
    <input ngModel name=name [disabled]=fieldIsDisabled() />
</form>
this.ngForm.form.enable();
this.ngForm.form.disable();

This is the approach I wish I could use if it weren't for two problems:

  • formGroup.enable() ignores the fields' [disabled] directive value, therefore forcing all the fields to become enabled when other controls might be saying it should stay disabled. This is shown in the linked demo.
  • If the value in the [disabled] directive changes, the form fields won't care if I called enable() or disable(), which can cause fields to become enabled when I don't want them to.

I wish it instead worked like a control variable, like the next solution:

State variable present across all fields

Here, the formIsDisabled signal controls the entire form's "disabled" state. It fixes the previous solution's problem.

<form ngForm>
    <input ngModel name=name [disabled]="formIsDisabled() || nameDisabled()"/>
    <input ngModel name=address [disabled]=formIsDisabled() />
</form>

The disadvantage is that the control variable must be applied to every single field, which feels redundant and error-prone... but it's still the least bad option, to my knowledge.

Questions: is there a better way to achieve this? What reasons are there for the formGroup.enable() and formGroup.disable() methods to work like this?

1

There are 1 best solutions below

2
alexdefender93 On

The way to achieve that only using the DISABLED status:

For simplicity Let's say you have 1 dimensional reactive form. First, you need to disable all currently enabled fields and collect the disabled fields' keys:

    const alreadyDisadledKeys: string[] = [];
    Object.keys(this.form.controls).forEach((key) => {
      const control = this.form.controls[key];
      if (control.status === 'DISABLED') {
        alreadyDisadledKeys.push(key);
      } else {
        control.disable();
      }
    });

alreadyDisadledKeys can be stored somewhere. Then enable the form again, excluding alreadyDisadledKeys:

    Object.keys(this.form.controls).forEach((key) => {
      const control = this.form.controls[key];
      if (!alreadyDisadledKeys.includes(key)) {
        control.enable();
      }
    });

The same approach can be extended for more complicated forms too, you would need to do the same steps:

  • Collet all disabled fields ( or all enabled fields if you prefer )
  • Iterate over the form and disable the rest of the fields
  • Iterate again and enable previously enabled fields

What reasons are there for the formGroup.enable() and formGroup.disable() methods to work like this?

Here I can only guess. I think it's because Angular treats DISABLED more of a status than an attribute.