Учитывая этот код:
this.form = this.formBuilder.group({
email: ['', [Validators.required, EmailValidator.isValid]],
hasAcceptedTerms: [false, Validators.pattern('true')]
});
Как я могу получить все ошибки проверки this.form
?
Я пишу модульные тесты и хочу включить в сообщение подтверждения фактические ошибки проверки.
angular
typescript
validation
Орлиный клюв
источник
источник
Ответы:
Я столкнулся с той же проблемой, и для поиска всех ошибок проверки и их отображения я написал следующий метод:
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]); }); } }); }
Название формы
productForm
следует изменить на ваше.Это работает следующим образом: мы получаем все наши элементы управления из формы в формате
{[p: string]: AbstractControl}
и выполняем итерацию по каждому ключу ошибки, чтобы получить подробную информацию об ошибке. Пропускаетnull
значения ошибок.Его также можно изменить для отображения ошибок проверки в представлении шаблона, просто замените
console.log(..)
на то, что вам нужно.источник
' + controlErrors[keyErrors];
вместо', controlErrors[keyErrors];
?ValidationErrors
в angular 2?import { ValidationErrors } from '@angular/forms';
Это решение с
FormGroup
внутренними опорами ( как здесь )Проверено на: Angular 4.3.6
получить-формы-проверки-ошибок.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; }
Пример использования :
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; }
источник
controlErrors
т.е.if (controlErrors) {
проверка только наnull
выдаст ошибку, если ошибки естьundefined
Это еще один вариант, который рекурсивно собирает ошибки и не зависит от какой-либо внешней библиотеки, например
lodash
(только ES6):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; } }
источник
Рекурсивный способ получения всех ошибок из формы Angular , после создания любой формулярной структуры нет возможности получить все ошибки из формы. Это очень полезно для целей отладки, а также для построения графиков этих ошибок.
Протестировано для 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; } }
источник
form.errors ?? null
мне пришлось удалить символ ?? для его компиляции. Что еще более важно, в условии проверки FormGroup я добавил,|| formParameter instanceof FormArray
что действительно открыло мое приложение. Благодарность!Или вы можете просто использовать эту библиотеку для получения всех ошибок, даже из глубоких и динамических форм.
Если вы хотите использовать статическую функцию в своих формах
import {NaoFormStatic} from '@naologic/forms'; ... const errorsFlat = NaoFormStatic.getAllErrorsFlat(fg); console.log(errorsFlat);
Если вы хотите использовать,
NaoFromGroup
вы можете импортировать и использовать егоimport {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"}}
Прочтите полную документацию
источник
Основываясь на ответе @MixerOID , вот мое окончательное решение в качестве компонента (возможно, я создам библиотеку). Я также поддерживаю 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; } } }
И HTML:
<div *ngIf="formRef.submitted"> <div *ngFor="let error of errors" class="text-danger"> {{getErrorMessage(error)}} </div> </div>
Применение:
<app-form-errors [form]="languageForm" [formRef]="formRef" [messages]="{language: 'Language'}"> </app-form-errors>
источник
Попробуйте это, он вызовет проверку для всех элементов управления в форме:
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); } }); }
источник
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; } }
Я взял его у Деборак и немного изменил.
источник
// 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);
источник
Вы можете перебирать свойство this.form.errors.
источник
this.form.errors
возвращает только ошибки проверки дляthis.form
, а не дляthis.form.controls
. Вы можете проверять FormGroups и их дочерние элементы (произвольное количество FormGroups, FormControls и FormArrays) отдельно. Чтобы получить все ошибки, я думаю, вам нужно задавать их рекурсивно.Для большого дерева FormGroup вы можете использовать lodash, чтобы очистить дерево и получить дерево только элементов управления с ошибками. Это делается путем повторения через дочерние элементы управления (например, с помощью
allErrors(formGroup)
) и удаления любых полностью действительных подгрупп элементов управления: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; } }
источник
Я использую angular 5, и вы можете просто проверить свойство статуса вашей формы с помощью FormGroup, например
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 будет "НЕДЕЙСТВИТЕЛЬНЫМ", если все поля не пройдут все правила проверки.
Самое приятное то, что он обнаруживает изменения в режиме реального времени.
источник