web-dev-qa-db-fra.com

Obtenez les validateurs présents dans FormGroup / FormControl

J'utilise Material 2 dans mon application, mais dans cette question, je veux résoudre un problème spécifiquement avec Input .

Comme vous pouvez le voir dans Référence de l'API , il existe une liaison de propriété appelée required, qui apparaît sous la forme d'un astérisque dans l'espace réservé.

Donc, je me demande s'il existe un moyen de vérifier si le contrôle de formulaire a un validateur spécifique dans Angular, parce que je ne veux vraiment pas définir manuellement pour chaque entrée [required]="true/false"

J'ai lu les documents AbstractControl et je n'ai rien trouvé à ce sujet. J'ai rencontré la hasError méthode (qui ironiquement n'est pas documentée dans nulle part ... ni dans FormGroup ni dans FormControl ni dans AbstractControl), mais ce n'est pas ce que je recherche. Il vérifie simplement si le contrôle de formulaire contient l'erreur, mais comme vous l'avez peut-être lu, je veux vérifier si le contrôle a des validateurs spécifiques ...

Du code:

<md-input-container>
  <input placeholder="Placeholder" 
         mdInput [formControl]="anyCtrl" 
         [required]="anyCtrl.hasValidator('required')"> <!-- something like this -->
</md-input-container>

J'espère que la question est suffisamment claire. Merci d'avance.

15
dev_054

Angular ne fournit pas vraiment une excellente façon de le faire, mais c'est possible. Je pense que les validateurs sont stockés dans un service qui est injecté dans FormBuilder (NG_VALIDATORS), et je vais chercher à détourner ce service ou à l'injecter dans un composant, mais pour l'instant cela fonctionnera:

Les docs et la source montrent un membre validator sur AbstractControl tapé à ValidatorFn. ValidatorFn a malheureusement simplement un typage null, donc nous ne pouvons pas voir ce qui se passe. Cependant, après avoir fouillé la source générée et sondé une application, il semble que nous pouvons passer à cette méthode validators un paramètre control, qui renverra un objet de tous les validateurs présents sur ce contrôle, indépendamment de que ça passe ou non.

Étrangement, cela uniquement fonctionne sur le FormControl lui-même et non sur le FormGroup (sur le FormGroup , le membre validators n'est pas une fonction et a toujours été null dans mes tests). Le JS compilé dit que cette fonction prend un paramètre control; J'ai essayé de transmettre des références FormControl mais pour autant que je sache, cela ne fera que renvoyer les validateurs sur le contrôle tant que ce paramètre n'est pas nul.

Obtenir des validateurs sur un FormControl

// in the constructor
this.myForm = this.formBuilder.group({
  'anyCtrl': ['', Validators.required],
  'anotherCtrl': ['', Validators.compose([Validators.required, Validators.email])]
});

// later on 
let theValidators = this.myForm.controls['anyCtrl'].validator('');
console.log(theValidators) // -> {required: true};

let otherValidators = this.myForm.controls['anotherCtrl'].validator('');
console.log(otherValidators); // -> {required: true, email: true}

Rendre plus facile à saisir:

public hasValidator(control: string, validator: string): boolean {
  return !!this.myForm.controls[control].validators(control).hasOwnProperty(validator);
 // returns true if control has the validator
}

et dans votre balisage:

<md-input-container>
  <input placeholder="Placeholder" 
         mdInput [formControl]="anyCtrl" 
         [required]="hasValidator('anyCtrl', 'email')">
</md-input-container>

Cas spécial pour Validators.required

Le validateur required a un raccourci. Le [required] la liaison est en fait une instance de la directive RequiredValidator (ligne 5022 de source/forms.js). Cette directive ajoutera en fait le validateur required au FormControl sur lequel il est activé. Cela revient à ajouter Validators.required au FormGroup lors de l'initialisation. Ainsi, la définition de la propriété liée sur false supprimera le validateur required de ce contrôle et vice versa ... dans tous les cas, la directive affecte le FormControl.required value, donc la lier à une propriété qu'elle change ne fera pas grand-chose.

La seule différence est que le [required] la directive ajoute l'astérisque à l'espace réservé tandis que Validators.required ne fait pas.

Je vais continuer à chercher NG_VALIDATORS, mais j'espère que cela aide pour l'instant!

21
joh04667

Cette réponse est une continuation de @ joh04667's . Ils ont écrit:

public hasValidator(control: string, validator: string): boolean {
  return !!this.myForm.controls[control].validators(control).hasOwnProperty(validator);
 // returns true if control has the validator
}

Cependant, il n'y a pas de méthode AbstractControls.validators(). Je suppose que AbstractControls.validator() était voulu.

La méthode hasValidator() ne fonctionne que pour les validateurs qui "échouent" (par exemple, un validateur requis sur un contrôle avec la valeur "" (vide)). Car s'ils passent, ils renvoient null. Un moyen de contourner ce problème serait de définir la valeur afin qu'elle échoue toujours et de la restaurer ensuite.

public hasValidator(control: string, validator: string): boolean {
    let control: AbstractControl = this.myForm.controls[control];
    let lastValue: any = control.value;
    switch(validator) {
        case 'required':
            control.setValue('');  // as is appropriate for the control
        case 'pattern':
            control.setValue('3'); // given you have knowledge of what the pattern is - say its '\d\d\d'
        ....
    }
    let hasValidator: boolean = !!control.validator(control).hasOwnProperty(validator);

    control.setValue(lastValue);
    return hasValidator;
}

Et c'est assez horrible. Cela pose la question - Pourquoi n'y a-t-il pas de AbstractControl.getValidators(): ValidatorFn[]|null?

Quelle est la motivation pour cacher cela? Peut-être craignent-ils que quelqu'un insère leur code:

...
secretPassword: ['', [Validators.pattern('fjdfjafj734738&UERUEIOJDFDJj')]
...
1
HankCa