Compte tenu de ce code:
this.form = this.formBuilder.group({
email: ['', [Validators.required, EmailValidator.isValid]],
hasAcceptedTerms: [false, Validators.pattern('true')]
});
Comment puis-je obtenir toutes les erreurs de validation this.form
?
J'écris des tests unitaires et je souhaite inclure les erreurs de validation réelles dans le message d'assert.
angular
typescript
validation
EagleBeak
la source
la source
Réponses:
J'ai rencontré le même problème et pour trouver toutes les erreurs de validation et les afficher, j'ai écrit la méthode suivante:
getFormValidationErrors() { Object.keys(this.productForm.controls).forEach(key => { const controlErrors: ValidationErrors = this.productForm.get(key).errors; if (controlErrors != null) { Object.keys(controlErrors).forEach(keyError => { console.log('Key control: ' + key + ', keyError: ' + keyError + ', err value: ', controlErrors[keyError]); }); } }); }
Le nom du formulaire
productForm
doit être remplacé par le vôtre.Cela fonctionne de la manière suivante: nous obtenons tous nos contrôles du formulaire au format
{[p: string]: AbstractControl}
et itérons par chaque clé d'erreur, pour obtenir les détails de l'erreur. Il ignorenull
les valeurs d'erreur.Il peut également être modifié pour afficher les erreurs de validation sur la vue du modèle, il suffit de le remplacer
console.log(..)
par ce dont vous avez besoin.la source
' + controlErrors[keyErrors];
au lieu de', controlErrors[keyErrors];
?ValidationErrors
dans angular 2?import { ValidationErrors } from '@angular/forms';
C'est une solution avec des
FormGroup
supports intérieurs ( comme ici )Testé sur: Angular 4.3.6
get-form-validation-errors.ts
import { AbstractControl, FormGroup, ValidationErrors } from '@angular/forms'; export interface AllValidationErrors { control_name: string; error_name: string; error_value: any; } export interface FormGroupControls { [key: string]: AbstractControl; } export function getFormValidationErrors(controls: FormGroupControls): AllValidationErrors[] { let errors: AllValidationErrors[] = []; Object.keys(controls).forEach(key => { const control = controls[ key ]; if (control instanceof FormGroup) { errors = errors.concat(getFormValidationErrors(control.controls)); } const controlErrors: ValidationErrors = controls[ key ].errors; if (controlErrors !== null) { Object.keys(controlErrors).forEach(keyError => { errors.push({ control_name: key, error_name: keyError, error_value: controlErrors[ keyError ] }); }); } }); return errors; }
En utilisant l'exemple :
if (!this.formValid()) { const error: AllValidationErrors = getFormValidationErrors(this.regForm.controls).shift(); if (error) { let text; switch (error.error_name) { case 'required': text = `${error.control_name} is required!`; break; case 'pattern': text = `${error.control_name} has wrong pattern!`; break; case 'email': text = `${error.control_name} has wrong email format!`; break; case 'minlength': text = `${error.control_name} has wrong length! Required length: ${error.error_value.requiredLength}`; break; case 'areEqual': text = `${error.control_name} must be equal!`; break; default: text = `${error.control_name}: ${error.error_name}: ${error.error_value}`; } this.error = text; } return; }
la source
controlErrors
c.- à -if (controlErrors) {
d. Que la vérification uniquementnull
donnera une erreur si des erreurs sontundefined
Ceci est une autre variante qui collecte les erreurs de manière récursive et ne dépend d'aucune bibliothèque externe comme
lodash
(ES6 uniquement):function isFormGroup(control: AbstractControl): control is FormGroup { return !!(<FormGroup>control).controls; } function collectErrors(control: AbstractControl): any | null { if (isFormGroup(control)) { return Object.entries(control.controls) .reduce( (acc, [key, childControl]) => { const childErrors = collectErrors(childControl); if (childErrors) { acc = {...acc, [key]: childErrors}; } return acc; }, null ); } else { return control.errors; } }
la source
Méthode récursive pour récupérer toutes les erreurs d'une forme angulaire , après avoir créé tout type de structure de formulaire, il n'y a aucun moyen de récupérer toutes les erreurs du formulaire. Ceci est très utile à des fins de débogage mais aussi pour tracer ces erreurs.
Testé pour Angular 9
getFormErrors(form: AbstractControl) { if (form instanceof FormControl) { // Return FormControl errors or null return form.errors ?? null; } if (form instanceof FormGroup) { const groupErrors = form.errors; // Form group can contain errors itself, in that case add'em const formErrors = groupErrors ? {groupErrors} : {}; Object.keys(form.controls).forEach(key => { // Recursive call of the FormGroup fields const error = this.getFormErrors(form.get(key)); if (error !== null) { // Only add error if not null formErrors[key] = error; } }); // Return FormGroup errors or null return Object.keys(formErrors).length > 0 ? formErrors : null; } }
la source
form.errors ?? null
j'ai dû supprimer le ?? pour qu'il compile. Plus important encore, dans la condition de vérification FormGroup, j'ai ajouté|| formParameter instanceof FormArray
ce qui a vraiment ouvert mon application. Merci!Ou vous pouvez simplement utiliser cette bibliothèque pour obtenir toutes les erreurs, même à partir de formulaires profonds et dynamiques.
Si vous souhaitez utiliser la fonction statique sur vos propres formulaires
import {NaoFormStatic} from '@naologic/forms'; ... const errorsFlat = NaoFormStatic.getAllErrorsFlat(fg); console.log(errorsFlat);
Si vous souhaitez l'utiliser,
NaoFromGroup
vous pouvez l'importer et l'utiliserimport {NaoFormGroup, NaoFormControl, NaoValidators} from '@naologic/forms'; ... this.naoFormGroup = new NaoFormGroup({ firstName: new NaoFormControl('John'), lastName: new NaoFormControl('Doe'), ssn: new NaoFormControl('000 00 0000', NaoValidators.isSSN()), }); const getFormErrors = this.naoFormGroup.getAllErrors(); console.log(getFormErrors); // --> {first: {ok: false, isSSN: false, actualValue: "000 00 0000"}}
Lire la documentation complète
la source
Basé sur la réponse @MixerOID , voici ma solution finale en tant que composant (peut-être que je crée une bibliothèque). Je supporte également FormArray:
import {Component, ElementRef, Input, OnInit} from '@angular/core'; import {FormArray, FormGroup, ValidationErrors} from '@angular/forms'; import {TranslateService} from '@ngx-translate/core'; interface AllValidationErrors { controlName: string; errorName: string; errorValue: any; } @Component({ selector: 'app-form-errors', templateUrl: './form-errors.component.html', styleUrls: ['./form-errors.component.scss'] }) export class FormErrorsComponent implements OnInit { @Input() form: FormGroup; @Input() formRef: ElementRef; @Input() messages: Array<any>; private errors: AllValidationErrors[]; constructor( private translateService: TranslateService ) { this.errors = []; this.messages = []; } ngOnInit() { this.form.valueChanges.subscribe(() => { this.errors = []; this.calculateErrors(this.form); }); this.calculateErrors(this.form); } calculateErrors(form: FormGroup | FormArray) { Object.keys(form.controls).forEach(field => { const control = form.get(field); if (control instanceof FormGroup || control instanceof FormArray) { this.errors = this.errors.concat(this.calculateErrors(control)); return; } const controlErrors: ValidationErrors = control.errors; if (controlErrors !== null) { Object.keys(controlErrors).forEach(keyError => { this.errors.push({ controlName: field, errorName: keyError, errorValue: controlErrors[keyError] }); }); } }); // This removes duplicates this.errors = this.errors.filter((error, index, self) => self.findIndex(t => { return t.controlName === error.controlName && t.errorName === error.errorName; }) === index); return this.errors; } getErrorMessage(error) { switch (error.errorName) { case 'required': return this.translateService.instant('mustFill') + ' ' + this.messages[error.controlName]; default: return 'unknown error ' + error.errorName; } } }
Et le HTML:
<div *ngIf="formRef.submitted"> <div *ngFor="let error of errors" class="text-danger"> {{getErrorMessage(error)}} </div> </div>
Usage:
<app-form-errors [form]="languageForm" [formRef]="formRef" [messages]="{language: 'Language'}"> </app-form-errors>
la source
Essayez ceci, cela appellera la validation pour tous les contrôles sous forme:
validateAllFormControl(formGroup: FormGroup) { Object.keys(formGroup.controls).forEach(field => { const control = formGroup.get(field); if (control instanceof FormControl) { control.markAsTouched({ onlySelf: true }); } else if (control instanceof FormGroup) { this.validateAllFormControl(control); } }); }
la source
export class GenericValidator { constructor(private validationMessages: { [key: string]: { [key: string]: string } }) { } processMessages(container: FormGroup): { [key: string]: string } { const messages = {}; for (const controlKey in container.controls) { if (container.controls.hasOwnProperty(controlKey)) { const c = container.controls[controlKey]; if (c instanceof FormGroup) { const childMessages = this.processMessages(c); // handling formGroup errors messages const formGroupErrors = {}; if (this.validationMessages[controlKey]) { formGroupErrors[controlKey] = ''; if (c.errors) { Object.keys(c.errors).map((messageKey) => { if (this.validationMessages[controlKey][messageKey]) { formGroupErrors[controlKey] += this.validationMessages[controlKey][messageKey] + ' '; } }) } } Object.assign(messages, childMessages, formGroupErrors); } else { // handling control fields errors messages if (this.validationMessages[controlKey]) { messages[controlKey] = ''; if ((c.dirty || c.touched) && c.errors) { Object.keys(c.errors).map((messageKey) => { if (this.validationMessages[controlKey][messageKey]) { messages[controlKey] += this.validationMessages[controlKey][messageKey] + ' '; } }) } } } } } return messages; } }
Je l'ai pris à Deborahk et l' ai modifié un peu.
la source
// IF not populated correctly - you could get aggregated FormGroup errors object let getErrors = (formGroup: FormGroup, errors: any = {}) { Object.keys(formGroup.controls).forEach(field => { const control = formGroup.get(field); if (control instanceof FormControl) { errors[field] = control.errors; } else if (control instanceof FormGroup) { errors[field] = this.getErrors(control); } }); return errors; } // Calling it: let formErrors = getErrors(this.form);
la source
Vous pouvez parcourir la propriété this.form.errors.
la source
this.form.errors
ne renvoie que des erreurs de validation pour lethis.form
, pas pourthis.form.controls
. Vous pouvez valider FormGroups et ses enfants (nombre arbitraire de FormGroups, FormControls et FormArrays) séparément. Pour récupérer toutes les erreurs, je pense que vous devez leur demander de manière récursive.Pour une grande arborescence FormGroup, vous pouvez utiliser lodash pour nettoyer l'arborescence et obtenir une arborescence contenant uniquement les contrôles contenant des erreurs. Cela se fait en répétant via des contrôles enfants (par exemple en utilisant
allErrors(formGroup)
) et en élaguant tous les sous-groupes de contrôles pleinement valides:private isFormGroup(control: AbstractControl): control is FormGroup { return !!(<FormGroup>control).controls; } // Returns a tree of any errors in control and children of control allErrors(control: AbstractControl): any { if (this.isFormGroup(control)) { const childErrors = _.mapValues(control.controls, (childControl) => { return this.allErrors(childControl); }); const pruned = _.omitBy(childErrors, _.isEmpty); return _.isEmpty(pruned) ? null : pruned; } else { return control.errors; } }
la source
J'utilise angular 5 et vous pouvez simplement vérifier la propriété status de votre formulaire en utilisant FormGroup par exemple
this.form = new FormGroup({ firstName: new FormControl('', [Validators.required, validateName]), lastName: new FormControl('', [Validators.required, validateName]), email: new FormControl('', [Validators.required, validateEmail]), dob: new FormControl('', [Validators.required, validateDate]) });
this.form.status serait "INVALID" à moins que tous les champs passent toutes les règles de validation.
La meilleure partie est qu'il détecte les changements en temps réel.
la source