42

I am using Angular Material 2's mat-datepicker and want the input element disabled so the user cannot edit the value using the text input.

There are detailed instructions in the Angular Material 2 docs on how to disable different parts of the mat-datepicker however, these do not seem to cover how to disable the text input when it is part of a reactive form.

The Angular Material docs suggest you disable the text input in the following way:

<mat-form-field>
  <!-- Add the disabled attribute to the input element -->
  <input
    disabled
    matInput
    [matDatepicker]="dateJoined"
    placeholder="Date joined"
    formControlName="dateJoined"
  >
  <mat-datepicker-toggle matSuffix [for]="dateJoined"></mat-datepicker-toggle>

  <!-- Add [disabled]=false to the mat-datepicker -->                  
  <mat-datepicker
    [disabled]="false"
    startView="year"
    #dateJoined
  ></mat-datepicker>
</mat-form-field>

However, if your datepicker is part of a reactive form the text element remains active and you get the following message 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. Example: form = new FormGroup({ first: new FormControl({value: 'Nancy', disabled: true})});

I updated the FormGroup in the component to disable the FormControl, which has the desired effect of disabling the input, however, if you then get the value of the FormGroup using this.form.value the disabled form control is no longer present.

Is there a work around for this which does not involve having a separate template driven form using ngModel just for the mat-datepicker(s)?

EDIT: added “read-only” to post title to clarify this isn’t about disabling the control - because what I was asking about was to make the input element read-only, but not disable to control itself

PaulBunion
  • 346
  • 2
  • 18
nclarx
  • 847
  • 1
  • 8
  • 18

3 Answers3

90

To create a disabled FormControl is really simple.

1 - Don't use disabled attribute in your template;

2 - Instantiate your FormGroup like this:

this.formGroup = this.formBuilder.group({
  dateJoined: { disabled: true, value: '' }
  // ...
});

That being said, although you want to prevent users from typing something in the input, you still want to let them select a date by clicking the button (more specifically in matSuffix), right?

If it's correct, disable doesn't work for this case, because it'll disable all the input (including the button in matSuffix).

To solve your case, you can use readonly. Instantiate the FormGroup normally and then in template:

<input                          
  matInput 
  readonly <- HERE
  [matDatepicker]="dateJoined" 
  placeholder="Date joined" 
  formControlName="dateJoined">

DEMO

developer033
  • 24,267
  • 8
  • 82
  • 108
8

To expand on developer033's answer, to dynamically toggle the readonly state of the input, modify the readonly property using a component variable.

Dynamically Toggle Readonly

See Stackblitz Demo

app.component.html

<input matInput 
  [readonly]="inputReadonly"   <!-- Update `readonly` property using variable -->
  [matDatepicker]="dateJoined" 
  placeholder="Date joined" 
  formControlName="dateJoined">

app.component.ts

import {Component} from '@angular/core';
import {FormBuilder, FormGroup, Validators} from '@angular/forms';
import {VERSION} from '@angular/material';

@Component({
  selector: 'material-app',
  templateUrl: 'app.component.html'
})
export class AppComponent {
  formGroup: FormGroup;
  inputReadonly = true;
  version = VERSION;

  constructor(private formBuilder: FormBuilder) { }

  ngOnInit() {
    this.formGroup = this.formBuilder.group({
      dateJoined: ''
    });
  }

  public toggleInputReadonly() {
    this.inputReadonly = !this.inputReadonly;
  }
}
Christopher Peisert
  • 21,862
  • 3
  • 86
  • 117
  • Thanks for the additional information. Always great to point out that you can make the values of attributes dynamic when you need to. – nclarx Dec 06 '19 at 08:17
  • This works. I do not understand though, why the hover highlight when you place the mouse cursor on top of it while it is readonly. shouldn't it be disabled as well? – chitgoks Jul 06 '23 at 10:24
1

This helped us to disable input:

<mat-form-field appearance="fill">
    <mat-label>Input disabled</mat-label>
    <input matInput [matDatepicker]="dp3" disabled>
    <mat-datepicker-toggle matSuffix [for]="dp3"></mat-datepicker-toggle>
    <mat-datepicker #dp3 disabled="false"></mat-datepicker>
</mat-form-field>

Ref

Mohammad Zaid Pathan
  • 16,304
  • 7
  • 99
  • 130
  • Thanks for this answer, it made it clear I needed to clarify the title. What I was after was how to make the input element read only, but not disable the control – nclarx Dec 23 '20 at 21:18