web-dev-qa-db-fra.com

Désactiver la saisie de texte sur mat-datepicker lors de l'utilisation d'un formulaire réactif

J'utilise Angular Material 2's mat-datepicker et souhaite que l'élément d'entrée soit désactivé afin que l'utilisateur ne puisse pas modifier la valeur à l'aide de la saisie de texte.

Il y a instructions détaillées dans le Angular Material 2 docs sur la façon de désactiver différentes parties du mat-datepicker cependant, ceux-ci ne semblent pas expliquer comment désactiver la saisie de texte lorsqu'elle fait partie d'un formulaire réactif.

Les documents Angular Material suggèrent de désactiver la saisie de texte de la manière suivante:

<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>

Cependant, si votre sélecteur de date fait partie d'une forme réactive, l'élément de texte reste actif et vous obtenez le message suivant d'Angular:

Il semble que vous utilisiez l'attribut désactivé avec une directive de formulaire réactif. Si vous définissez désactivé sur true lorsque vous configurez ce contrôle dans votre classe de composants, l'attribut désactivé sera réellement défini dans le DOM pour vous. Nous vous recommandons d'utiliser cette approche pour éviter les erreurs "modifié après vérification". Exemple: form = new FormGroup ({first: new FormControl ({value: 'Nancy', disabled: true})});

J'ai mis à jour le FormGroup dans le composant pour désactiver le FormControl, ce qui a pour effet souhaité de désactiver l'entrée, cependant, si vous obtenez ensuite la valeur du FormGroup en utilisant this.form.value le contrôle de formulaire désactivé n'est plus présent.

Existe-t-il un moyen de contourner ce problème qui n'implique pas d'avoir un formulaire géré par modèle distinct en utilisant ngModel uniquement pour le ou les sélecteurs mat-date?

15
nclarx

Pour créer un FormControl désactivé, c'est vraiment simple.

1 - N'utilisez pas d'attribut désactivé dans votre modèle;

2 - Instanciez votre FormGroup comme ceci:

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

Cela étant dit, bien que vous vouliez empêcher les utilisateurs de taper quelque chose dans l'entrée, vous voulez quand même leur permettre de sélectionner une date en cliquant sur le bouton (plus précisément dans matSuffix), non?

Si c'est correct, disable ne fonctionne pas dans ce cas, car cela désactivera toutes les entrées (y compris le bouton dans matSuffix).

Pour résoudre votre cas, vous pouvez utiliser readonly. Instanciez le FormGroup normalement puis dans le modèle:

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

DEMO

42
developer033

Pour développer la réponse de developer0 , pour basculer dynamiquement l'état readonly de input, modifiez la propriété readonly à l'aide d'une variable de composant.

Basculer dynamiquement en lecture seule

Voir 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;
  }
}
1
Christopher Peisert