J'ai une application Angular 2 qui utilise le module ReactiveForms
pour gérer un formulaire qui utilise un validateur personnalisé. Le validateur reçoit un objet FormControl
. J'ai un quelques champs de saisie qui pourraient utiliser le même validateur personnalisé si seulement je connaissais le nom du champ lorsque le FormControl
était passé au validateur.
Je ne trouve aucune méthode ou propriété publique sur FormControl
qui expose le nom du champ de saisie. C'est assez simple pour voir sa valeur, bien sûr. Ce qui suit montre comment je voudrais l'utiliser:
public asyncValidator(control: FormControl): {[key: string]: any} {
var theFieldName = control.someMethodOfGettingTheName(); // this is the missing piece
return new Promise(resolve => {
this.myService.getValidation(theFieldName, control.value)
.subscribe(
data => {
console.log('Validation success:', data);
resolve(null);
},
err => {
console.log('Validation failure:', err);
resolve(err._body);
});
});
}
Nous pouvons utiliser .parent
bien, aujourd'hui ["_parent"]
(voir plus ci-dessous):
export const getControlName = (control: ng.forms.AbstractControl) =>
{
var controlName = null;
var parent = control["_parent"];
// only such parent, which is FormGroup, has a dictionary
// with control-names as a key and a form-control as a value
if (parent instanceof ng.forms.FormGroup)
{
// now we will iterate those keys (i.e. names of controls)
Object.keys(parent.controls).forEach((name) =>
{
// and compare the passed control and
// a child control of a parent - with provided name (we iterate them all)
if (control === parent.controls[name])
{
// both are same: control passed to Validator
// and this child - are the same references
controlName = name;
}
});
}
// we either found a name or simply return null
return controlName;
}
et maintenant nous sommes prêts à ajuster notre validateur définition
public asyncValidator(control: FormControl): {[key: string]: any} {
//var theFieldName = control.someMethodOfGettingTheName(); // this is the missing piece
var theFieldName = getControlName(control);
...
.parent
plus tard, ["_parent"]
à présentEn ce moment (aujourd'hui, maintenant), la version actuelle est:
Mais suite à ce problème: feat (forms): faire de 'parent' une propriété publique de 'AbstractControl'
Et comme déjà indiqué ici
Traits
- formulaires: faire de "parent" une propriété publique de "AbstractControl" (# 11855) (445e592)
- ...
nous pourrions plus tard changer le ["_parent"]
en .parent
Pour développer la réponse de Radim Köhler. voici une façon plus courte d'écrire cette fonction.
getControlName(c: AbstractControl): string | null {
const formGroup = c.parent.controls;
return Object.keys(formGroup).find(name => c === formGroup[name]) || null;
}
Depuis Angular 4.2.x, vous pouvez accéder au parent d'un FormControl
FormGroup
(et à ses contrôles) en utilisant la propriété publique parent :
private formControl: FormControl;
//...
Object.keys(this.formControl.parent.controls).forEach((key: string) => {
// ...
});
Vous avez deux options:
Avec l'aide du décorateur Attribute
:
constructor(@Attribute('formControlName') public formControlName) {}
Avec l'aide du décorateur Input
:
@Input() formControlName;
Pour l'utiliser, votre validation doit bien sûr être une directive.
Vous pouvez définir le nom du contrôle dans les validateurs:
this.form = this.fb.group({
controlName: ['', [Validators.required, (c) => this.validate(c, 'controlName')]]
});
Et alors:
validate(c: FormControl, name) {
return name === 'controlName' ? {invalid: true} : null;
}
Pas exactement ce que vous voulez, mais vous pouvez créer dynamiquement le validateur comme dans certains exemples.
comme
typeBasedValidator(controlName: string): ValidatorFn {
return(control: AbstractControl): {[key: string]: any} => {
// Your code using controlName to validate
if(controlName == "something") {
doSomething();
} else {
doSomethingElse();
}
}
}
Utilisez ensuite le validateur lors de la création du formulaire, en passant le nom du contrôle comme