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

Angular reactive form, Dynamic validator not updating control validity

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

 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

this function works well, once the username control gets a value, a Validators.required is added to the address control. However, despite the validator being added, the validity of the address control doesn't update so the control is still marked as valid.

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

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

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

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

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

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

since there may be dynamic controls that I don't know the name of, and don't want to set an observable for each of them.

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

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

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