首页 > 解决方案 > 在 Angular(v2 及更高版本)反应形式表单数组中获取无效控件

问题描述

this.from.valid 返回 false 我正在使用下面的这种方法来获取第一个无效控件并在我的组件中相应地抛出错误。这种方法可以在没有任何表单数组的情况下工作良好的表单组。

有没有办法找出表单数组的第一个无效控件

获取表单验证错误.ts

import {
    AbstractControl,
    FormArray,
    FormGroup,
    ValidationErrors
} from '@angular/forms';
export interface AllValidationErrors {
    control_name: string;
    error_name: string;
    error_value: any;
    control_modified: string;
}
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));
            control.markAsTouched({
                onlySelf: true
            });
        } else if (control instanceof FormArray) {
            for (const arrayControl of control.controls) {
                if (arrayControl instanceof FormGroup) {
                    errors = errors.concat(
                        getFormValidationErrors(arrayControl.controls)
                    );
                }
            }
        }

        const controlErrors: ValidationErrors = controls[key].errors;
        if (controlErrors !== null) {
            Object.keys(controlErrors).forEach((keyError) => {
                errors.push({
                    control_name: key,
                    error_name: keyError,
                    control_modified: beautifyControl(key),
                    error_value: controlErrors[keyError]
                });
            });
        }
    });
    return errors;
}


function beautifyControl(key: string): string {
    let result: string[] = [];
    const splitters = ['-', '_'] as const;

    if (key.includes(splitters[0])) result = key.split(splitters[0]);
    else if (key.includes(splitters[1])) result = key.split(splitters[1]);
    else result = key.replace(/([a-z])([A-Z])/g, '$1 $2').split(' ');

    return [
        ...result.map((e: string, i: number) => e[0].toUpperCase() + e.slice(1))
    ].join(' ');
}

使用示例:

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

标签: angulartypescriptvalidationangular-reactive-forms

解决方案


我觉得当 FormArray 是 FormControls 的 FormArray 时需要考虑,所以应该像

Object.keys(controls).forEach((key) => {
        const control = controls[key];
        if (control instanceof FormGroup) {
            errors = errors.concat(getFormValidationErrors(control.controls));
            control.markAsTouched({
                onlySelf: true
            });
        } else if (control instanceof FormArray) {
            for (const arrayControl of control.controls) {
                    //..call to your function directly..
                    errors = errors.concat(
                        getFormValidationErrors(arrayControl.controls)
            }
        }
        ...

所以你需要

  Object.keys(controls).forEach(key => {
    const control = controls[key];
    if (control instanceof FormGroup) {
        ...
    } else if (control instanceof FormArray) {
      let i: number = 0;
      for (const arrayControl of control.controls) {
        if (arrayControl instanceof FormGroup) {
          ...
        } else {  //add the case if the FormArray is a FormArray
                  //of a FormControls
          const obj = {};
          obj[key + '-' + i] = arrayControl;
          i++;
          errors = errors.concat(getFormValidationErrors(obj));
        }
      }
    }

我写了一个愚蠢而丑陋的堆栈闪电战


推荐阅读