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 calledenable()ordisable(), 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.
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:
alreadyDisadledKeys can be stored somewhere. Then enable the form again, excluding alreadyDisadledKeys:
The same approach can be extended for more complicated forms too, you would need to do the same steps:
Here I can only guess. I think it's because Angular treats DISABLED more of a status than an attribute.