4

I'm trying to disable a reactive input form control in angualr2 as disabled based on a variable "canDisable" from the component. My code looks something like this.

<input type="text" formControlName="CustomerName" Name="CustomerName" 
[disabled]="canDisable"/>

Unfortunately, it is not working as expected can anyone provide me the reason for it.

However, it is working fine If I do [attr.disabled]="canDisable".

   <input type="text" formControlName="CustomerName" Name="CustomerName" 
    [attr.disabled]="canDisable"/>
TylerH
  • 20,799
  • 66
  • 75
  • 101
Mahesh Bongani
  • 680
  • 7
  • 20

3 Answers3

3

After short investigation I've found out that setting disabled input in FormControl causes ReactiveErrors.disabledAttrWarning():

It looks like you're using the disabled attribute with a reactive form directive. If you set disabled to true
when you set up this control in your component class, the disabled attribute will actually be set in the DOM for
you. We recommend using this approach to avoid 'changed after checked' errors.

  Example: 
  form = new FormGroup({
    first: new FormControl({value: 'Nancy', disabled: true}, Validators.required),
    last: new FormControl('Drew', Validators.required)

According to this comment it seems like another official solution for doing this is invoking FormControl.disable() method manually and the mentioned reason is again about change detection. I agree it can be considered as a bug... And there is also some explanation about it in angular/material2 repository: https://github.com/angular/material2/issues/2667#issuecomment-275280698

As you can see in the docs: Disabled controls are exempt from validation checks and are not included in the aggregate value of their ancestor controls. - maybe this is another reason to do it explicitly.

Daniel Kucal
  • 8,684
  • 6
  • 39
  • 64
3

[disabled] is property binding. It seems the angular team does not allow anymore to use this within Reactive Forms. To disable it, you need to use the disable() method from the FormControl

on the other hand it seems to me that they didn't apply the same behavior when you bind via attribute binding => [attr.disabled] (I don't know whether it's a bug or if they did this on purpose as most people use property binding more than attribute binding

So I would say that the reason you're looking for is this: angular team has blocked the use of the disabled property binding but not the disable attribute binding on Reactive Forms.

You can see this discussion about the use of property binding and see that some people used attribute binding to "solve their problem" but no one from angular team said a thing about it.

The reason why using disabled on Reactive Forms through attribute binding works and with property binding doesn't is something that you need to ask to Angular Team. You can open an issue about it.

Alexander Abakumov
  • 13,617
  • 16
  • 88
  • 129
Elmer Dantas
  • 4,649
  • 5
  • 30
  • 36
0
import { AfterViewInit, ChangeDetectorRef, Directive, ElementRef, Input, Renderer2 } from "@angular/core";

@Directive({
    selector: "[customDisable]"
})
export class CustomDisableDirective implements AfterViewInit {

    private _isDisabled: boolean = false;

    @Input('value')
    set isDisabled(value) {
        this._isDisabled = value;
        this.changeDetector.markForCheck();
        this.changeDetector.detectChanges();
    }

    constructor(public el: ElementRef, private renderer: Renderer2, private changeDetector: ChangeDetectorRef) { }

    ngAfterViewInit(): void {
        // Force the control to disable
        this.renderer.setProperty(this.el.nativeElement, 'disabled', this._isDisabled);
    }

}