【问题标题】:Reactive Form Always Valid, Even When Not. Nested Children in Form反应形式总是有效的,即使不是。表单中的嵌套子级
【发布时间】:2020-10-21 00:34:25
【问题描述】:

我在这个问题上看到了一些 StackOverflow 问题,但似乎没有一个问题的答案有效。

我正在使用 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]
 })

(所有控件都是这种情况)

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

如果需要,以下是有关此特定表格的更多信息:

Cannot Find Control with Path Using ngIf on Recursive Angular Form

Angular Deeply Nested Reactive Form: Cannot find control with path on nested FormArray

【问题讨论】:

  • 我感觉这只是在您的控件中实现验证器接口的问题。我想我可以稍后再看看,但如果你在那之前成功了,请告诉我。
  • 会的。我也会调查一下。截至目前,我正在尝试的方法似乎过于复杂。检查子组件中的表单验证,然后向父组件发送一个 true 或 false 备份。并非在所有情况下都有效,我认为有更好的方法

标签: angular typescript angular-forms


【解决方案1】:

Stackblitz demo

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

validate(c: AbstractControl) => ValidationErrors;

如果控件有效,则方法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 并仅依赖外部表单验证。

【讨论】:

  • 一如既往地感谢您...这几乎可以按预期完美运行。唯一的问题是当您第一次单击“添加组”时,在添加附加条件之前它不会注册为无效。我尝试在组控制组件中将_addCondition(... fn 更改为以下内容:` _addCondition() { this._conditionsFormArray.push(this._fb.control({ variable: null}, Validators.required )); }` ,但这并没有改变这个问题
  • 这是预期的行为,因为通常情况下,表单在用户与其交互之前被认为是有效的。但是如果你愿意,你可以将它们标记为脏,然后它们将是无效的。
  • 我明白了,我忘记了。有没有办法将其设置为默认值?在用户输入内容之前保持 from 无效?我尝试添加this._form.setErrors({ invalid: true }),但它只是暂时为假,然后又恢复为真
  • 我正在重新考虑它。由于我们正在动态构建整个事物,我认为每当我们添加控件时都应该调用验证。我今天再看看……一两个小时后。
  • 谢谢你,一如既往。我非常感谢!这是一个更好的方法
猜你喜欢
  • 2021-03-15
  • 1970-01-01
  • 2020-10-20
  • 2016-11-07
  • 1970-01-01
  • 1970-01-01
  • 2021-04-02
  • 2013-12-11
  • 1970-01-01
相关资源
最近更新 更多