Angesichts dieses Codes:
this.form = this.formBuilder.group({
email: ['', [Validators.required, EmailValidator.isValid]],
hasAcceptedTerms: [false, Validators.pattern('true')]
});
Wie kann ich alle Validierungsfehler erhalten this.form
?
Ich schreibe Unit-Tests und möchte die tatsächlichen Validierungsfehler in die Assert-Nachricht aufnehmen.
angular
typescript
validation
EagleBeak
quelle
quelle
Antworten:
Ich bin auf dasselbe Problem gestoßen, und um alle Validierungsfehler zu finden und anzuzeigen, habe ich die nächste Methode geschrieben:
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]); }); } }); }
Der Formularname
productForm
sollte in Ihren geändert werden.Es funktioniert folgendermaßen: Wir erhalten alle Steuerelemente aus dem Formular im Format
{[p: string]: AbstractControl}
und iterieren mit jedem Fehlerschlüssel, um Details zum Fehler abzurufen. Es werdennull
Fehlerwerte übersprungen.Es kann auch geändert werden, um Validierungsfehler in der Vorlagenansicht anzuzeigen. Ersetzen
console.log(..)
Sie es einfach durch das , was Sie benötigen.quelle
' + controlErrors[keyErrors];
statt', controlErrors[keyErrors];
?ValidationErrors
in Winkel 2 importieren ?import { ValidationErrors } from '@angular/forms';
Dies ist eine Lösung mit
FormGroup
Innenstützen ( wie hier )Getestet am: Angular 4.3.6
get-form-validation-error.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; }
Am Beispiel :
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; }
quelle
controlErrors
dhif (controlErrors) {
die Überprüfung für nurnull
einen Fehler geben , wenn Fehler sindundefined
Dies ist eine weitere Variante, die die Fehler rekursiv sammelt und nicht von einer externen Bibliothek wie
lodash
(nur ES6) abhängt :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; } }
quelle
Rekursive Methode zum Abrufen aller Fehler aus einem Angular-Formular . Nach dem Erstellen einer Formelstruktur gibt es keine Möglichkeit, alle Fehler aus dem Formular abzurufen. Dies ist sehr nützlich für Debugging-Zwecke, aber auch zum Zeichnen dieser Fehler.
Getestet auf Winkel 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; } }
quelle
form.errors ?? null
Ich musste das ?? damit es kompiliert. Noch wichtiger ist, dass ich in der FormGroup-Prüfbedingung hinzugefügt habe,|| formParameter instanceof FormArray
was meine Anwendung wirklich geöffnet hat. Vielen Dank!Oder Sie können diese Bibliothek einfach verwenden, um alle Fehler zu erhalten, auch von tiefen und dynamischen Formularen.
Wenn Sie die statische Funktion in Ihren eigenen Formularen verwenden möchten
import {NaoFormStatic} from '@naologic/forms'; ... const errorsFlat = NaoFormStatic.getAllErrorsFlat(fg); console.log(errorsFlat);
Wenn Sie verwenden möchten, können
NaoFromGroup
Sie es importieren und verwendenimport {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"}}
Lesen Sie die vollständige Dokumentation
quelle
Basierend auf der @ MixerOID- Antwort ist hier meine endgültige Lösung als Komponente (möglicherweise erstelle ich eine Bibliothek). Ich unterstütze auch FormArrays:
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; } } }
Und der HTML:
<div *ngIf="formRef.submitted"> <div *ngFor="let error of errors" class="text-danger"> {{getErrorMessage(error)}} </div> </div>
Verwendung:
<app-form-errors [form]="languageForm" [formRef]="formRef" [messages]="{language: 'Language'}"> </app-form-errors>
quelle
Versuchen Sie dies, es wird die Validierung für alle Steuerelemente in folgender Form aufgerufen:
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); } }); }
quelle
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; } }
Ich habe es von Deborahk genommen und ein wenig modifiziert.
quelle
// 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);
quelle
Sie können die Eigenschaft this.form.errors durchlaufen.
quelle
this.form.errors
gibt nur Validierungsfehler für das zurückthis.form
, nicht fürthis.form.controls
. Sie können FormGroups und seine untergeordneten Elemente (beliebige Anzahl von FormGroups, FormControls und FormArrays) separat überprüfen. Um alle Fehler abzurufen, müssen Sie sie meiner Meinung nach rekursiv abfragen.Bei einem großen FormGroup-Baum können Sie lodash verwenden, um den Baum zu bereinigen und einen Baum nur der Steuerelemente mit Fehlern abzurufen. Dies erfolgt durch Wiederholen durch untergeordnete Steuerelemente (z. B. Verwenden
allErrors(formGroup)
) und Bereinigen aller vollständig gültigen Untergruppen von Steuerelementen: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; } }
quelle
Ich verwende Winkel 5 und Sie können einfach die Statuseigenschaft Ihres Formulars mit FormGroup überprüfen, z
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 wäre "UNGÜLTIG", wenn nicht alle Felder alle Validierungsregeln erfüllen.
Das Beste daran ist, dass Änderungen in Echtzeit erkannt werden.
quelle