Angular 反应式表单至少验证字段不为空且 'lifecycle' 验证器

Angular reactive forms validate at least on field is not empty and 'lifecycle' of validator

我想验证至少一个字段 不是 空的表单 - 至少一个字段已归档。我创建了自定义验证器:

import { FormControl, FormGroup, ValidationErrors, ValidatorFn } from "@angular/forms";

export const pfkValidator: ValidatorFn = (abstractControl: AbstractControl): ValidationErrors | null => {
  let fg = (abstractControl as FormGroup);
  let isValid = false;
  Object.keys(fg.controls).forEach(
    field => {
      const ctrl = fg.get(field);
      if (ctrl instanceof FormControl) {
        console.log('ctrl value', ctrl.value);
        if (ctrl.value) {
          isValid = true;
        }
      }
    });

  if (isValid) return { 'valid': true }
  return null;
}

这是初始化表单的方式:

ngOnInit(): void {
    this.form = this.fb.group({
      Field1: [null],
      Field2: [null],
      Field3: [null],
      Field4: [null],
      Field5: [null],
      Field6: [null],
      Field7: [null],
      Field8: [null],
      Field9: [false],
      Field10: [false],
    }, { validators: pfkValidator });
}

问题是当表单加载时,每个字段的验证都会被激活,这需要相当长的时间。我的表单有 10 个字段,我在控制台中记录了 10x10 个输入。

这是预期的行为吗?

下面是您的实现,它在控制台中显示了 121 条日志

Stackblitz demo

然而,在下面使用 FormArrays 的实现中,我尝试减少 运行 操作以避免循环 Demo using FormArrays。现在控制台最初仅显示 14 条日志,每次编辑 1 条日志。您甚至可以添加 updateOn: 'blur' 以进一步提高性能

export const pfkValidator: ValidatorFn = (
  abstractControl: AbstractControl
): ValidationErrors | null => {
  console.log("ctrl value", abstractControl.value.join(""));
  if (abstractControl.value.join("") !== "") {
    return { atLeastOne: false };
  }
  return null;
};

这可以像下面这样实现

export class AppComponent {
  form: FormGroup;
  constructor(private fb: FormBuilder) {}
  get fields() {
    return this.form.get("fields") as FormArray;
  }
  ngOnInit(): void {
    this.form = this.fb.group({
      fields: this.fb.array(
        [null, null, null, null, null, null, null, null, false, false],
        { validators: [pfkValidator] }
      )
    });
  }
}

并在 html

<form [formGroup]='form'>
  <ng-container formArrayName='fields'>
    <input *ngFor="let control of fields.controls; let i = index" [formControlName]="i">
  </ng-container>

</form>