【问题标题】:Angular reactive form, Dynamic validator not updating control validity角反应形式,动态验证器不更新控制有效性
【发布时间】:2022-01-02 07:15:09
【问题描述】:

所以我有一个表单,其中只有当另一个控件有值时才需要一个控件,为此我创建了以下结构

 profileGroup = this.fb.group({
username: [''],
address: [
  '',
  [
    (control: AbstractControl) => {
      if (this.profileGroup?.get('username')?.value) {
        return (Validators.required)(control);
      }
      return (Validators.nullValidator)(control);
    },
  ],
],

});

此函数运行良好,一旦username 控件获得值,Validators.required 就会添加到address 控件中。但是,尽管添加了验证器,但 address 控件的有效性不会更新,因此该控件仍标记为 valid

如果可能的话,我想避免使用类似的东西

this.profileGroup.get('username')?.valueChanges.subscribe(val=>{
  this.profileGroup.get('address')?.updateValueAndValidity()
})

因为可能存在我不知道名称的动态控件,并且不想为每个控件设置可观察对象。

这是一个工作示例的堆栈闪电战 https://stackblitz.com/edit/angular-10-formbuilder-example-m8qjq8?file=src/app/app.component.ts

【问题讨论】:

  • updateValueAndValidity() 是一个 AbstractControl 类方法,我想你可以为this.profileGroup 运行这个方法,它应该可以工作,让我知道你是怎么做的
  • 当您开始在地址字段中插入一个值时会发生什么,如果您删除您输入的内容,控件是否显示为有效?由于您仅在插入用户名时设置地址验证器,所以是什么阻止用户首先插入他的地址,然后再插入他的用户名?你将如何处理?不确定您是否愿意以及它是否符合您的需求,但我建议您在 init 和提交处理无效状态(错误消息或 css 更改等)的两个字段中添加所需的验证器 - 毕竟预期有效表单将填写用户名和地址字段。
  • @DeepakJha 您的意思是将其插入验证器的功能中?不,它不起作用
  • @MishaMashina 是的,如果我键入内容然后清除它,该控件会正确标记为无效。尽管用户名为空,但地址控件是否有值无关紧要,但如果用户名有某些内容,则必须要求地址
  • 读取您的 cmets,您是否从某些不受您控制的服务(例如某些 API)获取表单字段元素的名称?

标签: angular angular-reactive-forms formbuilder angular-validation angular-validator


【解决方案1】:

这个函数很好用,一旦用户名控件得到一个值,一个 Validators.required 就会被添加到地址控件中。但是,尽管添加了验证器,但地址控件的有效性并未更新,因此该控件仍被标记为有效。

好吧,事实并非如此。您已经为address FormControl 定义了一个custom 验证器,它在address FormControl 值更新时执行。 (PS:它不是动态验证器)

当您更新 username 时,与其关联的验证器及其祖先(在您的情况下为 profileGroup)被调用,同级 FormControl 验证器不会被触发。

当您执行以下代码时,您正在手动执行与address FormControl 关联的验证器,这不会更新 FormControl 的有效性。它只是执行与 FormControl 关联的验证器并返回它们的结果。

const validator = abstractControl.validator({} as AbstractControl);

为了更新兄弟,即address FormControl 的有效性,您必须将其称为updateValueAndValidity()

另一种选择是在 FormGroup 级别定义验证器,它将自动执行,您不必在任何 FormControl 上手动调用 updateValueAndValidity()但是,使用这种方法,验证错误将设置在 FormGroup 级别。

因为可能存在我不知道名称的动态控件,并且 不想为它们中的每一个设置一个 observable。

如果您不知道控件名称,您将如何在自定义验证器中使用它们,如下所示,username FormControl 被引用?

this.profileGroup?.get('username')?.value

有一种方法可以在 formControl 上调用 updateValueAndValidity(),而无需明确指定它的名称,但不会推荐它。您可以遍历profileGroup.controls 并在每个控件上执行updateValueAndValidity,然后是profileGroup 本身。您还必须注意将 {onlySelf: true, emitEvent: false} 选项传递给 updateValueAndValidity 以避免递归。

【讨论】:

  • 感谢您的回答,嗯 首先:我很困惑,为什么这不是动态验证器?第二:控件的名称在一个数组中我想我可以从那里得到名称,但正如我所说,我不认为最好为每个控件创建一个监听器来监听 valuechanges,因为可能有 1 或 20+
  • @Jhoan 为什么你认为它是一个动态验证器?也许这会帮助我回答你的问题。基本上,您刚刚创建了一个采用control 的函数,并基于某些逻辑返回错误对象{required: true} 或在没有错误的情况下返回null。也许this 会有所帮助。
  • 是的,我只是想,因为有时它是必需的,有时不是,它是一个动态验证器,谢谢你让我知道我的错误。顺便说一句,在组级别设置验证器解决了我的问题,谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-27
  • 2021-08-30
  • 1970-01-01
  • 2020-12-23
相关资源
最近更新 更多