使父 FormGroup 无效,直到嵌套 FormGroup 有效 - FormGroup 的自定义验证器

azu*_*net 6 typescript angular-validation angular angular7

我有一个用于动态创建表单的 Angular 7 项目。我有一个父 FormGroup,其中包含各种类型的嵌套 FormGroup。

我希望 ParentForm 无效,直到所有嵌套/子表单都有效(实际上希望它们提交但尚未到达)。

  this.parentForm = new FormGroup(this.subforms, { validators: allSubModulesValidValidator }); 
Run Code Online (Sandbox Code Playgroud)

this.subforms 是一个像这样的对象:

interface DynamicKeyFormGroup {
  [key: string]: FormGroup;
}

subforms: DynamicKeyFormGroup = {};
Run Code Online (Sandbox Code Playgroud)

我知道我的验证器是错误的,但我不知道如何为 FormGroup 和 FormControl 设计验证器。

我的想法是,我试图循环遍历所有 this.subForms 的属性(即嵌套的 FormGroups),然后检查它们的状态。如果有无效的,则将parentForm标记为无效。

const allSubModulesValidValidator: ValidatorFn = (control: FormGroup): ValidationErrors | null => {
  const controls = control.controls;
  for (const key in controls) {
    if (controls.hasOwnProperty(key)) {
      if (!(controls[key].status === 'valid')) {
        return { 'allSubModulesValid': true };
      }
    }
  }
  return null;
};
Run Code Online (Sandbox Code Playgroud)

回应评论。删除验证器后,父级有效,而子级无效: 子无效,父有效

Хри*_*тов 0

在我看来,这是角度上的一个错误,尽管如上面的评论所示,clearValidators这是预期的行为。

让我们看看发生了什么。

我假设您正在通过以下方式清除验证器(基于图像)

someControl.validator = null;
Run Code Online (Sandbox Code Playgroud)

这有点不合适,或者通过调用清除验证器函数,例如

someControl.clearValidators()
Run Code Online (Sandbox Code Playgroud)

根据角度源执行以下操作

  /**
   * Empties out the synchronous validator list.
   *
   * When you add or remove a validator at run time, you must call
   * `updateValueAndValidity()` for the new validation to take effect.
   *
   */
  clearValidators(): void {
    this.validator = null;
  }

Run Code Online (Sandbox Code Playgroud)

正如此处所见,GithubSource是相同的。

所以问题是这个状态清除不会更新控件及其父控件的状态。

为了在清除状态后修复此行为,您应该更新控件

someControl.clearValidators();
someControl.updateValueAndValidity();
Run Code Online (Sandbox Code Playgroud)

updateValueAndValidity将更新控件的当前状态,并通知父级FormGroup(如果有)。

@jb-nizet 在上面的注释中提供的示例:即使您清除验证器,stackBlitzsetValue也会工作,因为他正在调用控件的方法,该方法执行以下操作

      override setValue(value: TValue, options: {
        onlySelf?: boolean,
        emitEvent?: boolean,
        emitModelToViewChange?: boolean,
        emitViewToModelChange?: boolean
      } = {}): void {
        (this as {value: TValue}).value = this._pendingValue = value;
        if (this._onChange.length && options.emitModelToViewChange !== false) {
          this._onChange.forEach(
              (changeFn) => changeFn(this.value, options.emitViewToModelChange !== false));
        }
        this.updateValueAndValidity(options);
      }

Run Code Online (Sandbox Code Playgroud)

如Angular Source中所示,因此这将在内部调用updateValueAndValidity,从而更新状态。

3年后队长来了:D