反应形式总是有效的,即使不是。窗体中的嵌套子项

Reactive Form Always Valid, Even When Not. Nested Children in Form

我已经看到一些关于这个问题的 Whosebug 问题,但其中 none 似乎已经证明了有效的答案。

我正在使用 Angular 构建一个动态创建的响应式表单。 StackBlitz here。用户可以选择在组内添加“组”和“条件”。每个组都可以使用 FormArrays 进一步嵌套。

表单按预期工作。以下是表格的主要部分:

  1. AppComponent:主要的父组件
  2. GroupControlComponent:父级的子级。照顾所有组对象
  3. ConditionFormComponent:GroupControlComponent 的子组件。照顾组内的所有条件

这是基本对象的样子:

{
  // appcomponent level
  "statement": {
    //groupcontrol level
    "groups": [
      {
        // conditionform level
        "conjunctor": null,
        "conditions": [
          {
            "variable": null
          }
        ],
        "groups": []
      }
    ]
  }
}

当我设置验证时,我希望一切都是必需的。所以我在父组件和子组件上浏览了 FormBuilder,并在所有表单控件上将 Validators.required 设置为 true。

this._fb.control({
  conjunctor: null,
  conditions: [[], Validators.required],
  groups: [[], Validators.required]
 })

(所有控件都是这样)

问题是,表格现在 总是 有效。即使表格实际上无效。是否可以在使用嵌套子组件时检查表单有效性?

如果需要,这里有一些关于这个特定表格的更多信息:

Stackblitz demo

基本上您必须实现 Validator(不是 Validators - 复数)接口。它有一个强制方法:

validate(c: AbstractControl) => ValidationErrors;

如果控件有效,方法 validate 应该 return null,如果控件无效,方法 validate 应该 null

还有一件事是您必须以与提供 NG_VALUE_ACCESSOR.

相同的方式提供 NG_VALIDATORS(现在,使用复数)

总结:

@Component({
  ...

  providers: [
    ...
    {
      provide: NG_VALIDATORS,
      useExisting: forwardRef(() => GroupControlComponent),
      multi: true
    }
  ]
})
export class GroupControlComponent implements Validator {
  ...

  // Notice that we don't need to use the c parameter passed to the method.
  // We are using the `_form` instance property to verify what we need
  validate(c: AbstractControl): ValidationErrors {
    return this._form.valid ? null : {errors: 'form is invalid'}; 
  }
  ...
}

您必须对您的 GroupControlComponentConditionFormComponent 执行此操作。

[更新]:您还需要注意动态创建的控件。在组控件中,让我们看一下具有输入的单个组件:条件控件。而不是:

_addCondition() {
  this._conditionsFormArray.push(
    this._fb.control({variable: null})
  );
}

您应该使用检查 variable 有效性的验证器来初始化控件,因为与 variable 属性关联的基础控件只会在用户与内部输入交互后才进行检查ConditionFormComponent。所以,你应该这样写:

_addCondition() {
  this._conditionsFormArray.push(
    this._fb.control({variable: null}, 
      (c: AbstractControl) => 
          c.value && c.value.variable ? null : {'required': true}
    )
  );
}

这是检查 variable 属性有效性的验证函数:

(c: AbstractControl) => 
    c.value && c.value.variable ? null : {'required': true}

如果您不这样做,它将覆盖底层 ConditionForm 控件中的验证(表明需要输入)。您可能会遇到一种奇怪的状态,即外部形式(在 GroupControl 中)无效,但内部形式(在 ConditionForm 中)有效。当您在外部表单上验证它时,您基本上甚至可以删除内部表单中的 Validators.required 并仅依赖外部表单验证。