Comment trouver les contrôles invalides sous forme réactive angulaire 4

89

J'ai une forme réactive en angulaire comme ci-dessous:

this.AddCustomerForm = this.formBuilder.group({
    Firstname: ['', Validators.required],
    Lastname: ['', Validators.required],
    Email: ['', Validators.required, Validators.pattern(this.EMAIL_REGEX)],
    Picture: [''],
    Username: ['', Validators.required],
    Password: ['', Validators.required],
    Address: ['', Validators.required],
    Postcode: ['', Validators.required],
    City: ['', Validators.required],
    Country: ['', Validators.required]
});

createCustomer(currentCustomer: Customer) 
{
    if (!this.AddCustomerForm.valid)
    {
        //some app logic
    }
}

this.AddCustomerForm.valid renvoie false, mais tout semble bon.

J'ai essayé de trouver en vérifiant la propriété status dans la collection de contrôles. Mais je me demande s'il existe un moyen de trouver les invalides et de les afficher à l'utilisateur?

sa_
la source
Si vous souhaitez simplement afficher les champs avec une erreur, vous pouvez utiliser css pour mettre en évidence ou colorer les champs non valides. Chaque champ invalide a une classe "ng-invalid" ajoutée dans sa liste de classes
LookForAngular

Réponses:

168

Vous pouvez simplement parcourir chaque contrôle et vérifier l'état:

public findInvalidControls() {
    const invalid = [];
    const controls = this.AddCustomerForm.controls;
    for (const name in controls) {
        if (controls[name].invalid) {
            invalid.push(name);
        }
    }
    return invalid;
}
Max Koretskyi
la source
1
merci pour cela mais j'ai essayé cela et même cela ne renvoie rien ma forme est toujours invalide, c'est bizarre. Je veux dire que ce code a l'air bien, mais cela n'a aucun sens pourquoi form.valid renvoie false
sa_
qu'est-ce qui findInvalidControls()vous rend?
Max Koretskyi
1
il ne renvoie rien, invalide est vide. J'ai vérifié un par un dans l'écran de veille de débogage, tous les contrôles sont valides mais this.AddCustomerForm.valid retourne toujours false.
sa_
Je pense que j'ai découvert. il y a un champ de courrier électronique et une expression régulière, mais d'une manière ou d'une autre, l'état du contrôle est EN ATTENTE et cela pourrait en être la cause
sa_
6
@ AngularInDepth.com - si l'un des contrôles est un groupe de formulaires, votre fonction renverra le groupe de formulaires non valide et non le contrôle de formulaire spécifique qui n'est pas valide
john Smith
35

Je viens de lutter contre ce problème: chaque champ de formulaire est valide, mais le formulaire lui-même n'est toujours pas valide.

Il s'avère que j'avais défini «Validator.required» sur un FormArray où les contrôles sont ajoutés / supprimés dynamiquement. Ainsi, même si le FormArray était vide, il était toujours nécessaire et le formulaire était donc toujours invalide, même si chaque contrôle visible était correctement rempli.

Je n'ai pas trouvé la partie invalide du formulaire, car ma fonction 'findInvalidControls' ne vérifiait que FormControl et non FormGroup / FormArray. Alors je l'ai mis à jour un peu:

/* 
   Returns an array of invalid control/group names, or a zero-length array if 
   no invalid controls/groups where found 
*/
public findInvalidControlsRecursive(formToInvestigate:FormGroup|FormArray):string[] {
    var invalidControls:string[] = [];
    let recursiveFunc = (form:FormGroup|FormArray) => {
      Object.keys(form.controls).forEach(field => { 
        const control = form.get(field);
        if (control.invalid) invalidControls.push(field);
        if (control instanceof FormGroup) {
          recursiveFunc(control);
        } else if (control instanceof FormArray) {
          recursiveFunc(control);
        }        
      });
    }
    recursiveFunc(formToInvestigate);
    return invalidControls;
  }
Jette
la source
3
Réponse incroyablement utile. Merci beaucoup
Mikki
1
D'accord, réponse très utile.
nenea le
20

Sous DevTools dans Chrome, sélectionnez l'onglet Console.

Dans la commande de type d'invite de console:

document.getElementsByClassName('ng-invalid')

La sortie doit être similaire à ceci: entrez la description de l'image ici

Dans ce cas, le texte souligné est pour le contrôle de formulaire listen-address. Et le texte encerclé: .ng-invalidindique que le contrôle est invalide.

Remarque: testé en chrome

Mwiza
la source
2
cela me semble être la manière la plus directe de répondre à la question.
ckapilla
2
Vous m'avez évité de devenir fou, si seulement je pouvais vous acheter un verre
Adam Winnipass
3

Les formulaires et tous vos contrôles étendent la classe angulaire AbstractControl. Chaque implémentation a un accesseur aux erreurs de validation.

let errors = this.AddCustomerForm.errors
// errors is an instance of ValidatorErrors

La documentation de l'API contient toutes les références https://angular.io/api/forms/AbstractControl

Éditer

Je pensais que l'accesseur d'erreur fonctionnait de cette façon, mais ce lien vers github montre qu'il y a d'autres personnes qui pensaient la même chose que moi https://github.com/angular/angular/issues/11530

Dans tous les cas, en utilisant l'accesseur de contrôles, vous pouvez parcourir tous les formControls de votre formulaire.

Object.keys(this.AddCustomerForm.controls)
    .forEach( control => {
        //check each control here
        // if the child is a formGroup or a formArray
        // you may cast it and check it's subcontrols too
     })
LookForAngular
la source
1
cela retourne null même s'il y a des contrôles vides
sa_
1
Il doit renvoyer null lorsqu'il n'y a aucune erreur. Pouvez-vous publier votre modèle?
LookForAngular
Oui, cela ne fonctionnera pas, les différentes validations définies sur chaque contrôle de formulaire, ces contrôles de chaque formulaire contiennent leurs erreurs, le formulaire ne le fait pas. Vous devez itérer les contrôles comme Maximus a donné une réponse.
AJT82
Je peux accéder aux erreurs pour chaque contorls individuel comme this.form.controls ['Email']. Errors
Nazrul Muhaimin
@ AJT_82 en effet, le formulaire lui-même peut afficher des erreurs si un validateur a été défini pour le formGroup (vérifiez la documentation sur la validation de champ croisé, ce qui a du sens de valider sur le groupe et non dans le contrôle)
LookForAngular
3

Maintenant, dans angular 9, vous pouvez utiliser la méthode markAllAsTouched () pour afficher les validateurs de contrôles non valides:

this.AddCustomerForm.markAllAsTouched();
Rodrigo Jorge Baptista
la source
Je vais lui donner un +1, car cela m'a aidé à savoir ce que j'avais besoin de savoir --- ce qui est d'afficher des messages de validation lorsque l'utilisateur n'a pas nécessairement touché les entrées.
Sean Halls
1

Si vous n'avez pas beaucoup de champs dans le formulaire, vous pouvez simplement F12 et survoler le contrôle, vous pourrez voir le pop-up avec les valeurs vierges / touchées / valides du champ- "# fieldname.form-control.ng- untouched.ng-invalid ".

darshna mishra
la source
1

Je pense que vous devriez essayer d'utiliser this.form.updateValueAndValidity()ou essayer d'exécuter cette même méthode dans chacun des contrôles.

Javi Marzán
la source
1

essaye ça

 findInvalidControls(f: FormGroup) {
    const invalid = [];
    const controls = f.controls;
    for (const name in controls) {
      if (controls[name].invalid) {
        invalid.push(name);
      }
    }
    return invalid;
  }
Trilok Singh
la source
1

Cela enregistrera tous les noms des contrôles 😊

for (let el in this.ReactiveForm.controls) {
      if (this.ReactiveForm.controls[el].errors) {
        console.log(el)
      }
 }          

vous pouvez en faire un tableau ou une chaîne et afficher à l'utilisateur

tejas n
la source
0

J'ai pris la liberté d'améliorer le code AngularInDepth.com -s, afin qu'il recherche de manière récursive les entrées non valides dans les formes imbriquées également. Qu'il soit imbriqué par FormArray-s ou FormGroup-s. Entrez simplement le formGroup de niveau supérieur et il renverra tous les FormControls qui ne sont pas valides.

Vous pouvez éventuellement parcourir certains des contrôles de type "instanceof", si vous séparez le contrôle FormControl et l'ajout de fonctionnalités de tableau non valides dans une fonction distincte. Cela rendrait la fonction beaucoup plus propre, mais j'avais besoin d'une option globale et unique pour obtenir un tableau plat de tous les formControls invalides et c'est la solution!

findInvalidControls( _input: AbstractControl, _invalidControls: AbstractControl[] ): AbstractControl[] {
    if ( ! _invalidControls ) _invalidControls = [];
    if ( _input instanceof FormControl  ) {
        if ( _input.invalid ) _invalidControls.push( _input );
        return _invalidControls;
    }

    if ( ! (_input instanceof FormArray) && ! (_input instanceof FormGroup) ) return _invalidControls;

    const controls = _input.controls;
    for (const name in controls) {
        let control = controls[name];
        switch( control.constructor.name )
        {
            case 'AbstractControl':
            case 'FormControl':
                if (control.invalid) _invalidControls.push( control );
                break;

            case 'FormArray':
                (<FormArray> control ).controls.forEach( _control => _invalidControls = findInvalidControls( _control, _invalidControls ) );
                break;

            case 'FormGroup':
                _invalidControls = findInvalidControls( control, _invalidControls );
                break;
        }
    }

    return _invalidControls;
}

Juste pour ceux qui en ont besoin, afin qu'ils n'aient pas à le coder eux-mêmes.

Modifier # 1

Il a été demandé qu'il renvoie également FormArray-s et FormGroups invalides, donc si vous en avez également besoin, utilisez ce code

findInvalidControls( _input: AbstractControl, _invalidControls: AbstractControl[] ): AbstractControl[] {
    if ( ! _invalidControls ) _invalidControls = [];
    if ( _input instanceof FormControl  ) {
        if ( _input.invalid ) _invalidControls.push( _input );
        return _invalidControls;
    }

    if ( ! (_input instanceof FormArray) && ! (_input instanceof FormGroup) ) return _invalidControls;

    const controls = _input.controls;
    for (const name in controls) {
        let control = controls[name];
        if (control.invalid) _invalidControls.push( control );
        switch( control.constructor.name )
        {    
            case 'FormArray':
                (<FormArray> control ).controls.forEach( _control => _invalidControls = findInvalidControls( _control, _invalidControls ) );
                break;

            case 'FormGroup':
                _invalidControls = findInvalidControls( control, _invalidControls );
                break;
        }
    }

    return _invalidControls;
}
Karl Johan Vallner
la source
1
Je l'ai essayé, mais il ne trouve aucun FormGroup ou FormArray invalide ... seulement FormControl invalide. J'ai fait la même erreur ... voyez ma réponse.
Jette
J'ai amélioré ma réponse, pour l'adapter à votre cas d'utilisation.
Karl Johan Vallner
0

vous pouvez enregistrer la valeur du formulaire console.log(this.addCustomerForm.value), cela consolidera la valeur de tous les contrôles, puis les champs null ou "" (vides) indiquent les contrôles non valides

Sohail Anwar
la source