web-dev-qa-db-fra.com

Comment trouver les contrôles non valides sous forme réactionnelle angulaire 4

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 bien aller. 

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

28
sa_

Vous pouvez simplement parcourir chaque contrôle et vérifier le statut:

public findInvalidControls() {
    const invalid = [];
    const controls = this.AddCustomerForm.controls;
    for (const name in controls) {
        if (controls[name].invalid) {
            invalid.Push(name);
        }
    }
    return invalid;
}
53

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

Il s'avère que j'avais défini 'Validator.required' sur un tableau de types où les contrôles sont ajoutés/supprimés dynamiquement. Ainsi, même si le FormArray était vide, il était toujours requis et le formulaire était donc toujours invalide, même si tous les contrôles visibles étaient correctement remplis.

Je n'ai pas trouvé la partie invalide du formulaire, car ma fonction 'findInvalidControls' vérifiait uniquement 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
Jette

Les formes et toutes vos commandes é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

L'API Docs contient toutes les références https://angular.io/api/forms/AbstractControl

Modifier

Je pensais que l'accesseur d'erreur fonctionnait de cette façon, mais ce lien vers github montre qu'il existe 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
LookForAngular

J'ai pris la liberté d'améliorer le code AngularInDepth.com - s, afin qu'il recherche également de manière récursive des entrées non valides dans les formulaires imbriqués. Que ce soit imbriqué par FormArray-s ou FormGroup-s. Il suffit de saisir le groupe de formulaire de niveau supérieur et il renverra tous les formulaires de contrôle non valides. 

Vous pouvez éventuellement écarter certaines des vérifications de type "instanceof", si vous souhaitez séparer la vérification FormControl et l'ajout à la fonctionnalité de tableau non valide dans une fonction distincte. Cela rendrait la fonction beaucoup plus propre, mais il me fallait une option unique et globale pour obtenir un tableau à plat de tous les formControls non valides 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, ils n'ont donc pas à le coder eux-mêmes. 

Éditer # 1

Il a été demandé que le code retourne également FormArray-s et FormGroups invalides. Si vous en avez besoin également, 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;
}
0
Karl Johan Vallner

Si vous n'avez pas beaucoup de champs dans le formulaire, vous pouvez simplement F12 et survoler le contrôle, vous pourrez voir la fenêtre contextuelle avec les valeurs immaculées/touchées/valides du champ- .ng-untouched.ng-invalid ".

0
darshna mishra