【问题标题】:How to add custom validator to a FormArray?如何将自定义验证器添加到 FormArray?
【发布时间】:2020-01-07 16:26:50
【问题描述】:

我想在表单中添加自定义验证器,以防止 mat-step 切换到下一步。当我使用 FormGroups 时一切正常,但当我必须使用 FormArray 时无法实现验证。

我已经尝试了至少两种在表单初始化时分配验证器的变体:

  • 数组内部

statuses: this._formBuilder.array([this.createStatus()], defaultStatusValidator())

  • 在数组的父窗体内

this.productionLineStatuses = this._formBuilder.group({statuses: this._formBuilder.array([this.createStatus()])}, {validator: defaultStatusValidator()});

但是这种尝试会导致错误(可能是在强制转换验证器时):

TypeError: Cannot convert undefined or null to object 
    at Function.keys (<anonymous>)
    at FormGroup.validate [as validator] (default-status.directive.ts:6)
    at FormGroup._runValidator (forms.js:3438)
    at FormGroup.updateValueAndValidity (forms.js:3399)
    at new FormGroup (forms.js:4097)
    at FormBuilder.group (forms.js:7578)
    at CreateProductionLineComponent.ngOnInit (create-production-line.component.ts:31)

在以下情况下不会抛出错误,但验证器也无法正常工作。 这是我的其余代码和我的自定义验证器:

ngOnInit() {
    this.productionLineDetails = this._formBuilder.group({
      productType: ['', Validators.required],
      language: ['', Validators.required],
      name: ['', Validators.required],
      description: [''],
    });
    this.productionLineStatuses = this._formBuilder.group({
      statuses: this._formBuilder.array([
        this.createStatus()
      ])
    }, defaultStatusValidator());
    this.statuses = this.productionLineStatuses.get('statuses') as FormArray;
    this.statusError = false;
  }

验证者:

export function defaultStatusValidator(): ValidatorFn {
    return function validate (statuses: FormArray) {
    let defaultCounter = 0;
    Object.keys(statuses.value.controls).forEach(key => {
        const control = statuses.value.controls[key];

        if (control.value.default == true) {
            defaultCounter ++;
        }
      });
    return (defaultCounter > 1) ? {moreThanOneStatusIsDefault: true} : null;
    };
}

我应该如何正确地将验证器添加到 FormArray?

【问题讨论】:

  • 您尝试将 defaultStatusValidator 添加为验证器,但最终调用它而不是 defaultStatusValidator()。这就是你得到错误的原因。去掉执行函数调用的括号

标签: angular angular-material angular-forms angular-validation


【解决方案1】:

您已经考虑过您的 FormArray 是 FormControls 的 FormArray 还是 FormGroups 的 FormArray,但问题是您如何迭代控件,

两者的简单示例

export function customValidateArray(): ValidatorFn {
    return (formArray:FormArray):{[key: string]: any} | null=>{
      let valid:boolean=true;
      formArray.controls.forEach((x:FormControl)=>{
          valid=valid && x.value=="a"
      })
      return valid?null:{error:'Not all a'}
    }
  };

export function customValidateArrayGroup(): ValidatorFn {
    return (formArray:FormArray):{[key: string]: any} | null=>{
      let valid:boolean=true;
      formArray.controls.forEach((x:FormGroup)=>{
          valid=valid && x.value.name=="a" 
      })
      return valid?null:{error:'Not all name are a'}
    }
  };

你可以在stackblitz看到一个例子

注意:创建表单时,我使用了FormGroup、FormControl和FormArray的构造函数,但是你也可以使用FormBuilder。

注意 2:不必将 FormArray 包含在 FormGroup 中

【讨论】:

  • 关于注释2:你是什么意思? mat-step 每一步都使用 FormGrops。如何以其他方式使用它?即使有可能,我仍然会坚持使用父 FormGruop 以使模块中的所有代码保持一致。
  • 只是有几次我看到创建一个只有一个字段的formGroup,即FormArray,它是必要的)在stackblitz中你可以看到如何管理formArray,-迭代formArray.controls并将 for 的变量用作 formGroup 或 formControl-。无论如何,FormArray 也是 FormGroup,例如在 mat-steper 中,您可以使用 stepControl formArray 和 formGroup formArray.at(0) 和 formArray.at(1)。请参阅stackblitz.com/edit/angular-ejtr91?file=app/… 可以将 FormArray 视为 formControls/formGroup 的“数组”
猜你喜欢
  • 2020-05-29
  • 1970-01-01
  • 2014-12-03
  • 1970-01-01
  • 2017-07-26
  • 2020-03-06
  • 1970-01-01
  • 2021-12-23
  • 2011-04-15
相关资源
最近更新 更多