268

I already tried to follow the example of other answers from here and I did not succeed!

I created a reactive form (ie, dynamic) and I want to disable some fields at any given time. My form code:

this.form = this._fb.group({
  name: ['', Validators.required],
  options: this._fb.array([])
});

const control = <FormArray>this.form.controls['options'];
control.push(this._fb.group({
  value: ['']
}));

my html:

<div class='row' formArrayName="options">
  <div *ngFor="let opt of form.controls.options.controls; let i=index">
    <div [formGroupName]="i">
      <select formArrayName="value">
        <option></option>
        <option>{{ opt.controls.value }}</option>
      </select>
    </div>
  </div>
</div>

I reduced the code to facilitate. I want to disable the field of type select. I tried to do the following:

form = new FormGroup({
  first: new FormControl({value: '', disabled: true}, Validators.required),
});

not working! Does anyone have a suggestion?

rrd
  • 5,789
  • 3
  • 28
  • 36
Renato Souza de Oliveira
  • 4,236
  • 4
  • 20
  • 31
  • How could the select be disabled, when you are trying to disable some formcontrol called `first`?`:) – AT82 Mar 16 '17 at 19:47
  • It was just typo. I want to disable select. Can you help me? – Renato Souza de Oliveira Mar 16 '17 at 22:03
  • Could you reproduce a plunker? – AT82 Mar 17 '17 at 18:51
  • Are you trying to disable the whole select? And `value` is not a formArray, it's a formControlName. If you want `value` to be a formArray you would have to change it. Currently it's a formControlName. So if you want the whole select field to be disabled, just change `` – AT82 Mar 17 '17 at 19:23

24 Answers24

505
name: [{value: '', disabled: true}, Validators.required],
name: [{value: '', disabled: this.isDisabled}, Validators.required],

or

this.form.controls['name'].disable();
Vingtoft
  • 13,368
  • 23
  • 86
  • 135
Joche Wis
  • 5,174
  • 1
  • 9
  • 4
  • 1
    if I set a value like that -> country: [ { value: this.address.country, disabled: true } ] the value do not fill – Silvio Troia Mar 17 '20 at 11:17
  • I have used the same technique to disable fields that were auto filled from trusted sources. I have a switch to enable/disable the form, and after enabling the whole form, I usually disable those fields using `if` statements. After the form is submitted, entire form is disabled once again. – retr0 Jun 16 '20 at 16:45
  • 1
    As @retr0 said, typically you would have to enable them right before you consume the entire form for, say, submit the data to the back-end, so there is no chance that the user can enter any data from the moment you enable them and the moment you send the data out of the component. – WinterBoot Feb 12 '21 at 20:54
  • I want set null for value and also disable. How to do it? I used `` this.form.patchvalue({ dropDown: [{value: null , disbaled: true}] }); `` But it doesnt disable but value set null. Any idea – Ranindu Oct 28 '21 at 13:51
  • there is a `this.form.get(controlName)` function which can be used in nested form as well by joining the path with `.` so `nestedForm.nestedControl` and do need to go trough controls :) – Filip Kováč Oct 31 '22 at 08:23
  • Note, that disabled fields are **not** included in `FormGroup.value`. Instead use [FormGroup.getRawValue](https://angular.io/api/forms/FormGroup#getrawvalue). Here's a nice [blog](https://indepth.dev/posts/1474/disable-form-controls-using-forms-api-or-html-attributes) – TmTron Feb 16 '23 at 12:40
141

Pay attention

If you are creating a form using a variable for condition and trying to change it later it will not work, i.e. the form will not change.

For example

this.isDisabled = true;
    
this.cardForm = this.fb.group({
    number: {value: null, disabled: this.isDisabled},
});

and if you change the variable

this.isDisabled = false;

the form will not change. You should use

this.cardForm.get('number').disable();

BTW.

You should use patchValue method for changing value:

this.cardForm.patchValue({
    number: '1703'
});
dab0bby
  • 2,951
  • 1
  • 31
  • 35
Dmitry Grinko
  • 13,806
  • 14
  • 62
  • 86
  • 1
    I faced the same problem, do you know why it is not working with variable? – Harshad Vekariya Sep 28 '20 at 10:33
  • 3
    @HarshadVekariya because you do not pass variable but just its value which is evaluated right inside constructor of abstractControl... – Filip Kováč Apr 16 '21 at 16:06
  • Thanks! I was trying to find documentation for this but I couldn't, where does it say we need to pass it in this form? {value: null, disabled: this.isDisabled} – user1328889 Apr 19 '21 at 11:01
  • 1
    Here's some details to what @Filip Kováč said. It has nothing to do with Angular, because it is basic behaviour of assigning literal value and storing it. Let's simplify example to plain JS to illustrate it: `this.a = true; let b = this.a; this.a = false; console.log(this.a); // false console.log(b); // true ` In this example, variable `b` got literal value `false` and maintains no reference to `this.a` which has provided this literal. – Rosty Oct 19 '22 at 12:21
55

I solved it by wrapping my input object with its label in a field set: The fieldset should have the disabled property binded to the boolean

 <fieldset [disabled]="isAnonymous">
    <label class="control-label" for="firstName">FirstName</label>
    <input class="form-control" id="firstName" type="text" formControlName="firstName" />
 </fieldset>
40

It is bad practice to use disable in a DOM with reactive forms. You can set this option in your FormControl, when you init the from

username: new FormControl(
  {
    value: this.modelUser.Email,
    disabled: true
  },
  [
    Validators.required,
    Validators.minLength(3),
    Validators.maxLength(99)
  ]
);

Property value is not necessary

Or you can get your form control with get('control_name')and set disable

this.userForm.get('username').disable();
Volodymyr Khmil
  • 1,078
  • 15
  • 13
  • 3
    Why is it a bad practice to use disable in the DOM with reactive forms? – pumpkinthehead Feb 26 '20 at 18:40
  • 7
    You will get a warning from angular. `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`. So the recommended way to change the disable/enable state directly via controls. Also, you can check this great topic https://netbasal.com/disabling-form-controls-when-working-with-reactive-forms-in-angular-549dd7b42110 – Volodymyr Khmil May 02 '20 at 17:55
  • 1
    @pumpkinthehead Because in reactive forms, the FormGroup is the Source of Truth, in template driven forms, the template is the Source of Truth. – GoTo Feb 11 '23 at 11:58
27
this.form.enable()
this.form.disable()

Or formcontrol 'first'

this.form.get('first').enable()
this.form.get('first').disable()

You can set disable or enable on initial set.

 first: new FormControl({disabled: true}, Validators.required)
Piece
  • 708
  • 13
  • 15
  • worked for me. Here is how to put the value in the control at same time. `new FormControl({ value: XXX, disabled: true })` – Paul G Jan 06 '22 at 21:23
26

The disabling FormControl prevents it to be present in a form while saving. You can just set it the readonly property.

And you can achieve it this way :

HTML :

<select formArrayName="value" [readonly] = "disableSelect">

TypeScript :

this.disableSelect = true;

Details here

Rhett Harrison
  • 430
  • 4
  • 19
Alex Po
  • 1,837
  • 1
  • 24
  • 28
11

A more general approach would be.

// Variable/Flag declare
public formDisabled = false;

// Form init
this.form = new FormGroup({
  name: new FormControl({value: '', disabled: this.formDisabled}, 
    Validators.required),
 });

// Enable/disable form control
public toggleFormState() {
    this.formDisabled = !this.formDisabled;
    const state = this.formDisabled ? 'disable' : 'enable';

    Object.keys(this.form.controls).forEach((controlName) => {
        this.form.controls[controlName][state](); // disables/enables each form control based on 'this.formDisabled'
    });
}
Herbi Shtini
  • 2,002
  • 29
  • 34
9

If you want to disable first(formcontrol) then you can use below statement.

this.form.first.disable();

Gampesh
  • 4,024
  • 2
  • 12
  • 9
7

If to use disabled form input elements (like suggested in correct answer how to disable input) validation for them will be also disabled, take attention for that!

(And if you are using on submit button like [disabled]="!form.valid"it will exclude your field from validation)

enter image description here

Oleksandr Yefymov
  • 6,081
  • 2
  • 22
  • 32
7

Providing disabled property as true inside FormControl surely disables the input field.

this.form=this.fb.group({
  FirstName:[{value:'first name', disabled:true}],
  LastValue:['last name,[Validators.required]]
})

The above example will disable the FirstName input field.

But real problem arises when you try to access disabled field value through form like this console.log(this.form.value.FirstName); and it shows as undefined instead of printing field's actual value. So, to access disabled field's value, one must use getRawValue() method provided by Reactive Forms. i.e. console.log(this.form.getRawValue().FirstName); would print the actual value of form field and not undefined.

Anant Shekhar
  • 101
  • 1
  • 5
  • getRawValue() - wow, I mean where is this in the docs. Thanks man - this did it for me. I needed to disable the input cause it has prefilled values. I want to pass them into the api params. I could not access them until I used `getRawValue()` - thanks! – Gel Jan 18 '22 at 21:12
4

This worked for me: this.form.get('first').disable({onlySelf: true});

4

I am just using

<input type="text" formControlName="firstName" [attr.disabled]="true || null" />

With this firstName stays accessible in form.value

Important: You have to use || null as the default value, so that angular can remove the attribute alltogether.

Dom
  • 333
  • 2
  • 5
3

The best solution is here:

https://netbasal.com/disabling-form-controls-when-working-with-reactive-forms-in-angular-549dd7b42110

Outline of solution (in case of broken link):

(1) Create a directive

import { NgControl } from '@angular/forms';

@Directive({selector: '[disableControl]'})
export class DisableControlDirective {

  @Input() set disableControl( condition : boolean ) {
    const action = condition ? 'disable' : 'enable';
    this.ngControl.control[action]();
  }

  constructor( private ngControl : NgControl ) {}
}

(2) Use it like so

<input [formControl]="formControl" [disableControl]="condition">

(3) Since disabled inputs do not show in form.value on submit you may need to use the following instead (if required):

onSubmit(form) {
  const formValue = form.getRawValue() // gets form.value including disabled controls
  console.log(formValue)
}
danday74
  • 52,471
  • 49
  • 232
  • 283
  • I tried this way. I'm showing most of my FormControls after pulling API data, so after setting/patching value to my formControl using `this.form.get('FIELD_NAME').patchValue(DYNAMIC_VALUE)` I show the formControl. when it passed to directive, it shows **Cannot read property 'disable' of undefined** – ImFarhad Jun 23 '20 at 08:29
2

enter image description here

lastName: new FormControl({value: '', disabled: true}, Validators.compose([Validators.required])),
Abdullah
  • 2,393
  • 1
  • 16
  • 29
1

If you have a form group, just display the form group. Then all formcontrols are disabled.

formGroup = new FormGroup({
     firstName: new FormControl(''),
     lastName: new FormControl(''),
});
this.formGroup.disable();
Bigeyes
  • 1,508
  • 2
  • 23
  • 42
1

You can also use attr.disabled for checkbox or radio in html without coding in .ts file, like this:

<input type="checkbox" id="hasDataACheck" formControlName="hasDataA" />
<label class="form-check-label" for="hasDataACheck">
    has Data A
</label>

<input type="text" formControlName="controlA" [attr.disabled]="
  form.get('hasDataA').value ? null : '' />
0

I had the same problem, but calling this.form.controls['name'].disable() did not fixed it because I was reloading my view (using router.navigate()).

In my case I had to reset my form before reloading:

this.form = undefined; this.router.navigate([path]);

Tai Truong
  • 668
  • 1
  • 8
  • 11
0

I was trying to get values from the localstorage and I wanted the email and password fields to be disabled. This worked for me:

email: new FormControl({value: localStorage.getItem("email"), disabled:true},[
      Validators.required,
      Validators.minLength(3),
    ]),
password: new FormControl({value: localStorage.getItem("password"), disabled:true},[
      Validators.required,
      Validators.minLength(3),
    ])
0

Angular 14+

field = new FormControl<any>()

readonly formGroup = new FormGroup<any>({
    field2: new FormControl<any>(),
});

Option 1

 ngOnInit() {
    # ...
    this.field.setDisable();
    this.field.setEnable();
    this.formGroup.controls.field2.setEnable();
    this.formGroup.controls.field2.setDisabled();
    # ...
}

Option 2

private setFieldEnabled() {
    this.field.setEnable()
  }

private setFieldDisabled() {
    this.field.setDisable()
  }

private setField2Enabled() {
    this.formGroup.controls.breakdown.setEnable();
  }

private setField2Disabled() {
    this.formGroup.controls.breakdown.setDisable();
  } 

setEnableOrDisableFields(truth: boolean): void {
    if (truth) {
        this.setFieldEnabled()
        this.setField2Enabled();
        return
    }
    this.setFieldDisabled()
    this.setField2Disabled();
}
0

You cannot disable the input control using disabled attribute in the reactive forms. The best solution for this is you can simply add a fieldset element and insert the input control in the fieldset element. After that you can easily disable or enable the fieldset element using typescript.

For ex.

index.html

<fieldset [disabled]="variable_name">
    <input name="name" formcontrolname="name">
</fieldset

index.ts

 variable_name:boolean;

 if(condition):
 {
     variable_name=true;
 }
 else
  {
     variable_name=false;
  }

This would easily help you to dynamically hide or show the input control

  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Nov 10 '22 at 05:59
-1

To make a field disable and enable of reactive form angular 2+

1.To disable

  • Add [attr.disabled]="true" to input.

<input class="form-control" name="Firstname" formControlName="firstname" [attr.disabled]="true">

To enable

export class InformationSectionComponent {
formname = this.formbuilder.group({
firstname: ['']
});
}

Enable whole form

this.formname.enable();

Enable particular field alone

this.formname.controls.firstname.enable();

same for disable, replace enable() with disable().

This Works fine. Comment for queries.

Srinivasan N
  • 733
  • 8
  • 9
-1

You can declare a function to enable/disable all of the form control:

  toggleDisableFormControl(value: Boolean, exclude = []) {
    const state = value ? 'disable' : 'enable';
    Object.keys(this.profileForm.controls).forEach((controlName) => {
      if (!exclude.includes(controlName))
        this.profileForm.controls[controlName][state]();
    });
  }

and use it like this

// disbale all field but email
this.toggleDisableFormControl(true, ['email']);
Duong Le
  • 258
  • 2
  • 6
-1

while making ReactiveForm:[define properety disbaled in FormControl]

 'fieldName'= new FormControl({value:null,disabled:true})

html:

 <input type="text" aria-label="billNo" class="form-control" formControlName='fieldName'>
Rohit
  • 101
  • 7
-4

you can do it easily by adding a css class and bind it to with angular.

.disable{
    pointer-events: none;
}
    <div [ngClass]="{'disable': //condition goes here">
     <input type="text" formControlName="test">
     </div>
Majid Hajibaba
  • 3,105
  • 6
  • 23
  • 55
Ursa Uits
  • 1
  • 1