web-dev-qa-db-fra.com

Comment obtenir le nom du champ d'entrée de l'objet Angular2 FormControl?

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);
          });
    });
  }
24
Michael Oryl

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ésent

En ce moment (aujourd'hui, maintenant), la version actuelle est:

2.1.2 (2016-10-27)

Mais suite à ce problème: feat (forms): faire de 'parent' une propriété publique de 'AbstractControl'

Et comme déjà indiqué ici

2.2.0-beta.0 (2016-10-20)

Traits

  • formulaires: faire de "parent" une propriété publique de "AbstractControl" (# 11855) (445e592)
  • ...

nous pourrions plus tard changer le ["_parent"] en .parent

20
Radim Köhler

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;
}
19
Chris

Depuis Angular 4.2.x, vous pouvez accéder au parent d'un FormControlFormGroup (et à ses contrôles) en utilisant la propriété publique parent :

private formControl: FormControl;

//...

Object.keys(this.formControl.parent.controls).forEach((key: string) => {
  // ...
});
3
Steve Brush

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.

3
Bazinga

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

0
dabicho