Cannot disable matInput element with [formControlName]

85,619

Solution 1

If you are using a FormGroup, then you should not disable the form in the HTML Template. It will not work if you try to disable in HTML together with FormControl. Instead, it should be done within the FormGroup. Try this:

  template: `
    <mat-form-field [formGroup]="form">
      <input matInput placeholder='Name' [formControlName]="formControlName">
    </mat-form-field>
  `

and:

ngOnInit() {
    this.form = this.fb.group({
        name: new FormControl({ value: '', disabled: this.disabled })
    });
}

Also...not a big deal but..you should really be doing:

public form: FormGroup;

instead of:

public form: any;

Don't forget the import as well

import { FormGroup, FormControl } from '@angular/forms';

Btw, the name inside of the form group declaration should match whatever you have set in the HTML. So:

<input formControlName="myInputName">

and

this.form = this.fb.group({
    myInputName....
});

Solution 2

 <mat-form-field fxFlex>    
   <input matInput placeholder="No" formControlName="no" readonly>    
 </mat-form-field>

Have you tried readonly option. This works fine with me.

Working code: html:

 <mat-form-field fxFlex>    
   <input matInput placeholder="No" formControlName="no" readonly>    
 </mat-form-field>

Solution 3

I have had the same issue and I have solved it with *ngIf directive. If input should be disabled, make it disabled, remove its form binding and give its value manually. If it's not, than use your formControl as it is.

This is your template:

<mat-form-field [formGroup]="form">
  <input matInput placeholder='Name' [formControlName]="formControlName" [disabled]='disabled'>
</mat-form-field>

change it with:

<mat-form-field *ngIf="disabled">
  <input matInput placeholder='Name' [value]="form.formControlName" disabled='true'>
</mat-form-field>
<mat-form-field *ngIf="!disabled" [formGroup]="form">
  <input matInput placeholder='Name' [formControlName]="formControlName">
</mat-form-field>

Solution 4

-->output try this.

.html file

   <form name="fg" [formGroup]="fg" >
        <mat-form-field >
                  <input matInput placeholder="Email" formControlName="email">
           </mat-form-field>
    </form>

.ts file import this : import { FormBuilder, FormGroup, Validators } from '@angular/forms';

constructor(private _formBuilder: FormBuilder) { }



   this.fg= this._formBuilder.group({
        email :[
            {
              value : '[email protected]',
              disabled: true
            },
Validators.required
        ],

Solution 5

If you are using FormGroup you have to use disabled property creating your FormGroup/FormControl:

name: new FormControl({ value: '', disabled: this.disabled })

But if you want to disable/enable you can use this in your HTML:

<input type="text" formControlName="name" [attr.disabled]="isDisabled == true ? true : null" />
Share:
85,619
John
Author by

John

Personal project: rSchedule - typescript library for generating dates for a given recurrence schedule ts-decoders - typescript library for validating unknown inputs and generating nice error messages rx-controls - typescript library, inspired by Angular's ReactiveFormsModule, for simplifying web app forms Angular IsLoadingService - Angular service for tracking loading state of arbitrary data Angular RouterStoreService - Angular service for tracking the Angular router's state Angular SizeObserver - Angular service for applying styles to a DOM element based on it's rendered size in the browser

Updated on July 09, 2022

Comments

  • John
    John almost 2 years

    I'm using matInput and mat-form-field (@angular/material) in an Angular component, and I can't disable the matInput.

    A working example can be seen here.

    It seems likely that I'm missing something obvious, but for the life of me I can't figure out what. Is this a bug?

    If I remove [formControlName] from the CustomFormInputComponent, then I can successfully disable the matInput

    CustomFormInputComponent:

    import { Input, Component } from '@angular/core';
    import { FormGroup } from '@angular/forms';
    
    @Component({
      selector: 'app-custom-form-input',
      template: `
        <mat-form-field [formGroup]="form">
          <input matInput placeholder='Name' [formControlName]="formControlName" [disabled]='disabled'>
        </mat-form-field>
      `,
    })
    export class CustomFormInputComponent  {
      @Input() form: FormGroup;
      @Input() formControlName: string = 'name';
      @Input() disabled = false;
    }
    

    AppComponent:

    import { Component } from '@angular/core';
    import { FormBuilder } from '@angular/forms';
    
    @Component({
      selector: 'my-app',
      template: `
        <p>At least one of these inputs should be disabled, but none are :(</p>
    
        <app-custom-form-input [form]="form" [disabled]='true'></app-custom-form-input>
    
        <app-custom-form-input [form]="form" [disabled]="'disabled'"></app-custom-form-input>
      `,
    })
    export class AppComponent  {
      public form: any;
    
      constructor(private fb: FormBuilder) {}
    
      ngOnInit() {
        this.form = this.fb.group({
          name: ''
        })
      }
    }
    

    Any insights are greatly appreciated!

    Answer

    For a bit more context on David's answer: Angular updates DOM state based on the disabled status of a reactive form control. What I think is happening: angular is rendering the CustomFormInputComponent before the AppComponent and is rendering the component as disabled. Then the AppComponent is rendered and the form is built with the name control enabled. Angular then goes and un-disabled the DOM input element (which is behavior as designed).

  • John
    John over 6 years
    On what are you basing your assertion that "If you are using a FormGroup, then you should not disable the form in the HTML Template"? No where in the reactive form guide is this stated, so far as I can tell. What makes you think the behavior I'm experiencing isn't a bug?
  • John
    John over 6 years
    For example, multiple input elements can bind to the same form control (I think). It's not immediately obvious to me why I couldn't disable one of those inputs in the html, but leave the reactive form control enabled so that the other inputs binding to it still worked.
  • David Anthony Acosta
    David Anthony Acosta over 6 years
    Because in that same guide, you can clearly see that all the validation on reactive forms is taking place in the class, not in the HTML. Even something as simple as "required" is added in the component class in their examples. No where in their guide is it done in the HTML.... Otherwise why even use reactive forms
  • David Anthony Acosta
    David Anthony Acosta over 6 years
    I think you are a bit confused about how FormControl, FormGroup work.
  • David Anthony Acosta
    David Anthony Acosta over 6 years
    Also, it's not even an assertion. Angular has a built in console warning that basically says "HEY DON'T DO THAT, DO IT IN THE CLASS". Open your console when you attempt to disable an input with formControlName and you will see it. It's pretty clear it's not meant to be disabled in that way.
  • John
    John over 6 years
    Well A) I hadn't noticed that. Thanks! B) "We recommend using this approach to avoid 'changed after checked' errors." Clearly disabling via the DOM is supported, otherwise they would say "you must". Not recommend. But this does seem to explain what's happening. Angular is (probably) rendering the input element as disabled, and then enabling it after that when it builds the parent element.
  • David Anthony Acosta
    David Anthony Acosta over 6 years
    No, multiple elements cannot share the same FormControl. Recommended basically means must.For example, it's recommended you encrypt passwords. But it's not a must. Would you then not encrypt them and just say "Well it's recommended, it's not a must...."
  • Tatyana
    Tatyana almost 6 years
    @DavidAnthonyAcosta But if I change this.disabled value to false - my control stays disabled. Is there a way to undisable the control?
  • DeadPassive
    DeadPassive over 5 years
    @Tatyana - You can enable/disable form controls programmatically e.g. this.printForm.controls['title'].enable(); or this.printForm.controls['title'].disable()
  • yogesh chavan
    yogesh chavan over 4 years
    I have added a working sample but still down vote 🤐.
  • Irrfan23
    Irrfan23 over 4 years
    copy answer of @yogesh chavan
  • omostan
    omostan almost 4 years
    I don't understand people voting down this answer. It is one of the most accurate of all the answers besides @N_B answer if you're implementing angular material input. Both answers are the same and worked for me. I wonder why "David Anthony Acosta" anser is the accepted one. In my case, I am implementing *ngxPermissionsOnly and I couldn't combine *ngIf with it because it implements *ngIf under the hood. The solution was to use readonly instead of [disabled]="true". With all that said, I am voting both answers up.
  • Mohamad Al Asmar
    Mohamad Al Asmar over 3 years
    Hi, I know this is correct, but I have a different case, I want to conditionally disable form controls without losing their values. Example: I am loading some form data and manually filling some fields and I want these fields to become disabled, how do I do that without losing the value from FormGroup? Note that "this.myForm.get('formcontrol').disable();" will remove the value from FormGroup and I don't want it to be disabled initially unless I have a specific case.
  • Coder0997
    Coder0997 over 3 years
    did not know about 'readonly' property, worked for me.
  • Aditya Yada
    Aditya Yada over 3 years
    thanks a lot .I was unable to disable input using attribute . working fine by disabling using the form control name .this.form.get('fcn').disable() .
  • Willie
    Willie about 3 years
    Yogesh thank you. This was a one word fix for code I was already implementing. Much appreciated!
  • Ole
    Ole over 2 years
    I love this answer. Upvote!!