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> </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]
});
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.
En plus: Peut-être considéré comme sale, mais cela me convient:
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.