이 코드가 주어지면 :
this.form = this.formBuilder.group({
email: ['', [Validators.required, EmailValidator.isValid]],
hasAcceptedTerms: [false, Validators.pattern('true')]
});
모든 유효성 검사 오류를 this.form
어떻게 얻을 수 있습니까?
단위 테스트를 작성 중이며 어설 션 메시지에 실제 유효성 검사 오류를 포함하고 싶습니다.
답변
나는 같은 문제를 만났고 모든 유효성 검사 오류를 찾아서 표시하기 위해 다음 방법을 작성했습니다.
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(..)
필요한 항목으로 교체 하면됩니다.
답변
이것은 FormGroup
내부 지지대 가있는 솔루션입니다 ( 여기처럼 )
테스트 대상 : 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;
}
사용 예 :
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;
}
답변
이것은 오류를 재귀 적으로 수집하고 다음과 같은 외부 라이브러리에 의존하지 않는 또 다른 변형입니다 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;
}
}
답변
또는이 라이브러리를 사용하여 깊고 동적 인 양식에서도 모든 오류를 가져올 수 있습니다.
npm i @naologic/forms
자신의 양식에서 정적 함수를 사용하려는 경우
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);
}
});
}