J'ai un composant de contrôle de formulaire personnalisé dans mon application Angular, qui implémente l'interface ControlValueAccessor
.
Cependant, je souhaite accéder à l'instance FormControl
associée à mon composant. J'utilise des formulaires réactifs avec FormBuilder
et j'effectue un contrôle de formulaire à l'aide de l'attribut formControlName
.
SO, comment puis-je accéder à FormControl
instance de l'intérieur de mon composant de formulaire personnalisé?
Cette solution est née de la discussion dans le répertoire Angular). Assurez-vous de la lire ou mieux de participer si vous êtes intéressé par ce problème.
J'ai étudié le code de la directive FormControlName
et cela m'a inspiré pour écrire la solution suivante:
@Component({
selector: 'my-custom-form-component',
templateUrl: './custom-form-component.html',
providers: [{
provide: NG_VALUE_ACCESSOR,
useExisting: CustomFormComponent,
multi: true
}]
})
export class CustomFormComponent implements ControlValueAccessor, OnInit {
@Input() formControlName: string;
private control: AbstractControl;
constructor (
@Optional() @Host() @SkipSelf()
private controlContainer: ControlContainer
) {
}
ngOnInit () {
if (this.controlContainer) {
if (this.formControlName) {
this.control = this.controlContainer.control.get(this.formControlName);
} else {
console.warn('Missing FormControlName directive from Host element of the component');
}
} else {
console.warn('Can\'t find parent FormGroup directive');
}
}
}
J'injecte le parent FormGroup
au composant, puis j'obtiens le FormControl
spécifique en utilisant le nom du contrôle obtenu via la liaison formControlName
.
Cependant, sachez que cette solution est spécialement conçue pour le cas d'utilisation où la directive FormControlName
est utilisée sur l'élément Host. Cela ne fonctionnera pas dans d'autres cas. Pour cela, vous devrez ajouter une logique supplémentaire. Si vous pensez que cela devrait être traité par Angular, assurez-vous de visiter la discussion .
L'utilisation de formControlName
comme paramètre d'entrée ne fonctionne pas lors de la liaison via le [formControl]
directive.
Voici une solution qui fonctionne dans les deux sens sans aucun paramètre d'entrée.
export class MyComponent implements AfterViewInit {
private control: FormControl;
constructor(
private injector: Injector,
) { }
// The form control is only set after initialization
ngAfterViewInit(): void {
const ngControl: NgControl = this.injector.get(NgControl, null);
if (ngControl) {
this.control = ngControl.control as FormControl;
} else {
// Component is missing form control binding
}
}
}
Comme @Ritesh a déjà écrit dans le commentaire, vous pouvez passer le contrôle de formulaire en tant que liaison d'entrée:
<my-custom-form-component [control]="myForm.get('myField')" formControlName="myField">
</my-custom-form-component>
Et ensuite, vous pouvez obtenir une instance de contrôle de formulaire dans votre composant de formulaire personnalisé comme suit:
@Input() control: FormControl;
Pour tous ceux qui viennent ici en 2019, avec Angular 6/7, la solution qui ne déclenche pas d'avertissement de dépréciation est celle décrite dans cette réponse:
https://stackoverflow.com/a/56061527/13412
Pour plus de détails, regardez cette présentation , comme décrit ci-dessus.