Les ControlValueAccessors sont apparus au cours des derniers mois et je ne sais pas trop pourquoi ni quand je dois les utiliser au lieu d'utiliser @Input
avec mes formes réactives.
Voici un exemple de code pour montrer comment j'ai travaillé avec les formulaires réactifs jusqu'à présent :
@Component({
selector: 'app-my-component',
template: `<input [formControl]="form.get('specificControlName')" />`
// or the alternative method of [formGroup]="form" and formControlName="specificControlName"
})
export class MyComponent {
@Input() form: FormGroup; // passed in formGroup
ngOnInit() {
form.valueChanges.pipe(
// do rxjs magic here
).subscribe(value => {
// do something with the value
})
}
}
Les formulaires réactifs enregistrent l'état du formulaire, de sorte que je peux accéder à cet état même à partir des composants parents. Je peux également accéder à tous les différents NgControl
des attributs comme valid
, disabled
, dirty
et touched
.
Qu'apportent les ControlValueAccessors que cette façon de travailler avec les formulaires réactifs n'apporte pas ? Et quels sont les cas d'utilisation où les ControlValueAccessors fonctionnent mieux que les formulaires réactifs ? @Input
y @Output
en général ?
EDIT :
https://medium.com/angular-in-depth/angular-nested-reactive-forms-using-cvas-b394ba2e5d0d
Dans cet article, l'auteur mentionne les points suivants comme étant les principales différences :
Trois façons de mettre en œuvre des formulaires imbriqués :
...
- En passant un handle du FormGroup aux composants enfants via Input et en le référençant dans les templates enfants. Il existe quelques bons tutoriels à ce sujet.
Mais l'inconvénient de cette approche est que vous liez étroitement le groupe de formulaires parent à celui du groupe enfant.
- Utilisation des CVA composites.
Pour : Hautement réutilisable, portable. Meilleure encapsulation (les contrôles de formulaires internes du composant ne doivent pas nécessairement être visibles pour les composants parents). Ceci est mieux utilisé lorsque vous avez un grand nombre de modules de formulaire, ce qui est typiquement un grand projet.
Inconvénient : la nécessité de mettre en œuvre l'interface CVA entraîne un code passe-partout.
C'est intéressant, mais cela soulève quelques autres questions : Pourquoi et quand ne voulez-vous pas que vos contrôles de formulaires internes soient visibles pour le parent ? Que signifie "portable" ?
Aussi :
import { Component, OnInit } from '@angular/core';
import { ControlValueAccessor,NG_VALUE_ACCESSOR, NG_VALIDATORS, FormGroup,FormControl, Validator, Validators,AbstractControl, ValidationErrors } from "@angular/forms";
@Component({
selector: 'app-address-info',
templateUrl: './address-info.component.html',
styleUrls: ['./address-info.component.css']
})
export class AddressInfoComponent implements OnInit, ControlValueAccessor {
public addressForm: FormGroup = new FormGroup({
addressLine: new FormControl("",[Validators.required]),
areacode: new FormControl('', [Validators.required, Validators.maxLength(5)])
});
constructor() { }
ngOnInit() {
}
public onTouched: () => void = () => {};
writeValue(val: any): void {
val && this.addressForm.setValue(val, { emitEvent: false });
}
registerOnChange(fn: any): void {
console.log("on change");
this.addressForm.valueChanges.subscribe(fn);
}
registerOnTouched(fn: any): void {
console.log("on blur");
this.onTouched = fn;
}
setDisabledState?(isDisabled: boolean): void {
isDisabled ? this.addressForm.disable() : this.addressForm.enable();
}
}
lorsque vous passez dans un FormGroup
en un ControlValueAccessor
L'auteur initialise un nouveau composant FormGroup
à l'intérieur du composant avec la même structure que l'objet transmis. N'est-il pas préférable de passer simplement l'objet FormGroup
lui-même alors ? Ou quels sont les avantages de l'encapsulation ?
EDIT2 : Voici une vidéo intéressante sur le sujet :