0

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

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

});

这个函数很好用,一旦username 控件得到一个值,aValidators.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

4

1 回答 1

1

此功能运行良好,一旦用户名控件获得值,就会将 Validators.required 添加到地址控件中。但是,尽管添加了验证器,但地址控件的有效性不会更新,因此该控件仍被标记为有效。

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

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

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

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

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

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

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

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

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

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

于 2022-01-02T09:44:05.640 回答