web-dev-qa-db-fra.com

Héritage de la validation à l’aide de ControlValueAccessor dans Angular

J'ai un composant de contrôle de formulaire personnalisé (c'est une entrée glorifiée). La raison pour laquelle il s’agit d’un composant personnalisé tient à la facilité de modification de l’UI - c’est-à-dire que si nous modifions fondamentalement le style de nos contrôles d’entrée, il sera facile de propager le changement dans l’ensemble de l’application.

Nous utilisons actuellement Material Design dans Angular https://material.angular.io

quels styles contrôle très bien quand ils sont invalides.

Nous avons implémenté ControlValueAccessor afin de nous permettre de transmettre un formControlName à notre composant personnalisé, qui fonctionne parfaitement; le formulaire est valide/invalide lorsque le contrôle personnalisé est valide/invalide et que l'application fonctionne comme prévu.

Cependant, le problème est que nous devons styliser l'interface utilisateur à l'intérieur du composant personnalisé en fonction de son invalidité ou non, ce que nous ne semblons pas être en mesure de faire: l'entrée qui doit être stylisée n'est jamais validée. transmet simplement les données vers et depuis le composant parent.

COMPOSANT.ts

import { Component, forwardRef, Input, OnInit } from '@angular/core';
import {
    AbstractControl,
    ControlValueAccessor,
    NG_VALIDATORS,
    NG_VALUE_ACCESSOR,
    ValidationErrors,
    Validator,
} from '@angular/forms';

@Component({
  selector: 'app-input',
  templateUrl: './input.component.html',
  styleUrls: ['./input.component.css'],
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => InputComponent),
      multi: true
    }
  ]
})
export class InputComponent implements OnInit, ControlValueAccessor {
  writeValue(obj: any): void {
    this._value = obj;
  }
  registerOnChange(fn: any): void {
    this.onChanged = fn;
  }
  registerOnTouched(fn: any): void {
    this.onTouched = fn;
  }
  setDisabledState?(isDisabled: boolean): void {
    this.disabled = isDisabled;
  }

  get value() {
    return this._value;
  }

  set value(value: any) {
    if (this._value !== value) {
      this._value = value;
      this.onChanged(value);
    }
  }

  @Input() type: string;

  onBlur() {
    this.onTouched();
  }

  private onTouched = () => {};
  private onChanged = (_: any) => {};
  disabled: boolean;

  private _value: any;

  constructor() { }

  ngOnInit() {
  }

}

COMPONENT.html

<ng-container [ngSwitch]="type">
  <md-input-container class="full-width" *ngSwitchCase="'text'">
    <span mdPrefix><md-icon>lock_outline</md-icon> &nbsp; </span>
    <input mdInput placeholder="Password" type="text" [(ngModel)]="value" (blur)="onBlur()" />
  </md-input-container>
</ng-container>

exemple utiliser sur la page:

HTML:

<app-input type="text" formControlName="foo"></app-input>

TS:

this.form = this.fb.group({
        foo: [null, Validators.required]
    });
5
matthall74

Réponse trouvée ici:

Obtenez l'accès à FormControl à partir du composant de formulaire personnalisé dans Angular

Pas sûr que ce soit la meilleure façon de le faire, et j'aimerais que quelqu'un trouve une méthode plus jolie, mais le fait de lier l'entrée de l'enfant au contrôle de formulaire obtenu de cette manière a résolu nos problèmes.

3
matthall74

En plus: Peut-être considéré comme sale, mais cela me convient:

  1. laissez votre composant implémenter l'interface Validator. 2 Dans la fonction de validation, vous utilisez le controlcontainer pour accéder au contrôle de formulaire externe de votre composant.
  2. Suivez l'état du contrôle de formulaire parent (VALID/INVALID) à l'aide d'une variable.
  3. vérifier pour touché. et effectuez des actions de validation sur vos champs uniquement lorsque toucher est vrai et que le statut a changé.
1
SomeOne_1

Vous pouvez avoir accès à la variable NgControl via DI. NgControl a toutes les informations sur le statut de validation. Pour récupérer NgControl, vous ne devez pas fournir votre composant via NG_VALUE_ACCESSOR. Vous devez plutôt définir l'accesseur dans le constructeur.

@Component({
  selector: 'custom-form-comp',
  templateUrl: '..',
  styleUrls: ...
})
export class CustomComponent implements ControlValueAccessor {

   constructor(@Self() @Optional() private control: NgControl) {
     this.control.valueAccessor = this;
   }

   // ControlValueAccessor methods and others

   public get invalid(): boolean {
     return this.control ? this.control.invalid : false;
   }

   public get showError(): boolean {
      if (!this.control) {
       return false;
      }

      const { dirty, touched } = this.control;

      return this.invalid ? (dirty || touched) : false;
   }
}

Veuillez parcourir cet article pour connaître les informations complètes.

0
VJAI