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?


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

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

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


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
     })

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();

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 ".


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.


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

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


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

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

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.