programing

Angular 2 Form Group에서 모든 검증 오류를 가져옵니다.

itsource 2023. 3. 8. 23:29
반응형

Angular 2 Form Group에서 모든 검증 오류를 가져옵니다.

이 코드를 지정하면:

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내부 지지대(여기 참조)

테스트 대상: 각도 4.3.6

get-form-validation-displays.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;
}

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;
    }
}

이는 에러를 재귀적으로 수집하는 또 다른 변종이며 다음과 같은 외부 라이브러리에 의존하지 않습니다.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;
  }
}

또는 이 라이브러리를 사용하여 깊고 역동적인 형식에서도 모든 오류를 가져올 수 있습니다.

npm i @naologic/forms

자신의 양식에서 정적 기능을 사용하려면

import {NaoFormStatic} from '@naologic/forms';
...
const errorsFlat = NaoFormStatic.getAllErrorsFlat(fg); 
console.log(errorsFlat);

사용하고 싶은 경우NaoFromGroupImport하여 사용할 수 있습니다.

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"}}

매뉴얼 전문을 읽다

@Mixer 기반OID 응답: 컴포넌트로서의 최종 솔루션을 다음에 나타냅니다(라이브러리를 작성할 수도 있습니다).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>

[ Try This ]그럼 형식에서 모든 컨트롤에 대한 검증이 호출됩니다.

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);            
    }
  });
}

Andreas 코드를 사용하여 플랫오브젝트 내의 모든 에러 코드를 취득하여 표시되는 에러를 보다 쉽게 로깅할 수 있도록 조정했습니다.

다음 사항을 고려하십시오.

export function collectErrors(control: AbstractControl): any | null {
  let errors = {};
  let recursiveFunc = (control: AbstractControl) => {
    if (isFormGroup(control)) {
      return Object.entries(control.controls).reduce(
        (acc, [key, childControl]) => {
          const childErrors = recursiveFunc(childControl);
          if (childErrors) {
            if (!isFormGroup(childControl)) {
              errors = { ...errors, [key]: childErrors };
            }
            acc = { ...acc, [key]: childErrors };
          }
          return acc;
        },
        null
      );
    } else {
      return control.errors;
    }
  };
  recursiveFunc(control);
  return errors;
}

이.form.errors 속성을 반복할 수 있습니다.

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);

수락된 응답을 조정하여 문자열을 반환하고, 이 문자열은 콘솔에 인쇄할 수 있습니다.

function getFormValidationErrors(form: FormGroup): string {
    return Object.keys(form.controls)
        .map((control) => {
            const controlErrors = form.get(control).errors;
            if (!controlErrors) {
                return [];
            }
            const controlErrorsString = Object.keys(controlErrors)
                .flatMap(
                    (keyError) => `${keyError}: ${controlErrors[keyError]}`
                )
                .join(', ');
            return `${control}: {${controlErrorsString}}`;
        })
        .filter((list) => list.length > 0)
        .join('\n');
}

대형 Form Group 트리의 경우 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;
  }
}
**I met the same problem and for finding all validation errors and 
displaying only first error, I wrote next method:**

> first declare variable on top
  public errors: any = [];
  public fieldError: any = '';

> now subscribe form on noOnInit 
  
  this.form.valueChanges.subscribe(() => {
  this.showOnlyFirstError(this.form);
  this.errors = []
  });
  this.showOnlyFirstError(this.form);

> now call function

 showOnlyFirstError(form) {
 Object.keys(form.controls).forEach(key => {

 const controlErrors: ValidationErrors = form.get(key).errors;
 if (controlErrors != null) {
      Object.keys(controlErrors).forEach(keyError => {
        const showMessage = key + " is " + keyError
        this.errors.push(showMessage)
        this.fieldError = this.errors[0]
      });
     }
   });
 }

FormControls, FromGroups 및 FormArrays를 포함하는 매우 복잡한 FormGroup 컨트롤의 모든 오류를 제시해야 합니다.

간단한 솔루션을 작성하려고 했지만 모든 유형의 컨트롤을 지원하는 완벽한 솔루션을 찾을 수 없어서 다음과 같은 간단한 재귀 함수를 개발하여 모든 솔루션과 공유 중입니다.

export interface FieldError {
    formGroupName: string;
    fieldName: string;
    errorCode: string;
}

export function getFormErrors(
     control: AbstractControl, 
     formGroupName: string, 
     fieldName: string, 
     errors: FieldError[]) {

     if (control instanceof FormGroup) {
         Object.keys(control.controls).forEach(controlName => {
             let formControl = control.get(controlName);
             if (formControl) {
                 let fGroupName = formGroupName + "-" + controlName;
                 getFormErrors(formControl, fGroupName, controlName, errors);
             }
         })
     }

     if (control instanceof FormArray) {
         control.controls.forEach((fControl: AbstractControl, index) => {
             let fGroupName = formGroupName + "-" + index;
             getFormErrors(fControl, fGroupName, "Array", errors);
         })
     }

     if (control instanceof FormControl) {
         const controlErrors: ValidationErrors | null = control.errors;
         if (controlErrors) {
             Object.keys(controlErrors).forEach(errorCode => {
                 errors.push({
                     formGroupName: formGroupName,
                     fieldName: fieldName,
                     errorCode: errorCode
                 })
             });
         }
     }
 }

사용 방법은 다음과 같습니다.

    let errors: FieldError[] = []
    getFormErrors(YOUR_FORM_GROUP, "root", "", errors);

저는 angular 5를 사용하고 있으며, Form Group을 사용하여 폼의 상태 속성을 간단히 확인할 수 있습니다.

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는 "INVALID"가 됩니다.

가장 좋은 점은 실시간으로 변화를 감지한다는 것입니다.

언급URL : https://stackoverflow.com/questions/40680321/get-all-validation-errors-from-angular-2-formgroup

반응형