角度反应形式,动态验证器不更新控制有效性

Jho*_*a Q 6 formbuilder angular-validation angular angular-reactive-forms angular-validator

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

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

});

这个函数效果很好,一旦username 控件获得一个值,aValidators.required就会添加到address控件中。但是,尽管添加了验证器,但控件的有效性address并未更新,因此控件仍标记为valid

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

this.profileGroup.get('username')?.valueChanges.subscribe(val=>{
  this.profileGroup.get('address')?.updateValueAndValidity()
})
Run Code Online (Sandbox Code Playgroud)

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

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

Sid*_*ant 4

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

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

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

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

const validator = abstractControl.validator({} as AbstractControl);
Run Code Online (Sandbox Code Playgroud)

为了更新同级即addressFormControl 的有效性,您必须调用它的updateValueAndValidity().

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

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

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

this.profileGroup?.get('username')?.value
Run Code Online (Sandbox Code Playgroud)

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