Angular - 动态 add/remove 验证者

Angular - Dynamically add/remove validators

我有一个 FormGroup 定义如下:

this.businessFormGroup: this.fb.group({
    'businessType': ['', Validators.required],
    'description': ['', Validators.compose([Validators.required, Validators.maxLength(200)])],
    'income': ['']
  })

现在,当 businessTypeOther 时,我想从 description 中删除 Validators.required 验证器。如果 businessType 不是 Other,我想加回 Validators.required

我正在使用下面的代码来动态 add/remove Validators.required。但是,它会清除现有的 Validators.maxLength 验证器。

if(this.businessFormGroup.get('businessType').value !== 'Other'){
    this.businessFormGroup.get('description').validator = <any>Validators.compose([Validators.required]);               
} else {                
    this.businessFormGroup.get('description').clearValidators();               
}

this.businessFormGroup.get('description').updateValueAndValidity(); 

我的问题是,当 adding/removing 验证器为 required 时,如何保留现有验证器。

如果您使用 Angular 12.2 或更高版本,您可以使用 AbstractControl 方法 addValidatorsremoveValidatorshasValidatoras per the docs:

if(this.businessFormGroup.get('businessType').value !== 'Other'){
    this.businessFormGroup.get('description').addValidators(Validators.required);               
} else {                
    this.businessFormGroup.get('description').clearValidators();               
}

对于旧版本,Angular 表单有一个内置函数 setValidators() 可以启用验证器的编程分配。但是,这将覆盖您的验证器。

对于您的示例,您可以这样做:

if(this.businessFormGroup.get('businessType').value !== 'Other'){
    this.businessFormGroup.controls['description'].setValidators([Validators.required, Validators.maxLength(200)]);              
} else {                
    this.businessFormGroup.controls['description'].setValidators([Validators.maxLength(200)]);               
}
this.businessFormGroup.controls['description'].updateValueAndValidity();

请务必牢记,通过使用此方法,您将覆盖现有的验证器,因此您需要包括所有 need/want 的验证器控制你正在重置。

天真的方法是在条件变量发生变化时设置控件的验证器。但我们实际上可以通过使用一些间接 + 函数式编程来做得更好。

考虑作为布尔标志的 descriptionIsRequired getter 的存在。

想法:

  • 创建一个将 descriptionIsRequired 作为参数的自定义验证器函数,并根据它根据 required + maxLength 或 maxLength 验证控件。
  • 以这种方式将自定义验证器绑定到描述控件,以便在评估控件的有效性时,应考虑 descriptionIsRequired 的最新值。

第一点很容易实现:

function descriptionValidator(required: boolean): ValidatorFn {
  return (formControl: FormControl): ValidationErrors => {
    if (required) {
      return Validators.compose([Validators.required, Validators.maxLength(200)])(formControl);
    } else {
      return Validators.maxLength(200)(formControl);
    }
  }
}

注意这是一个自封装的函数

第二点有点棘手,但最后看起来是这样的:

export class FooComponent {
  constructor(){
    this.form = fb.group({
      description: ['initial name', this.validator()]
    });
  }

  private get descriptionIsRequired(): boolean {
   ...
  }

  private validator(): ValidatorFn {
    return (c: FormControl): ValidationErrors => descriptionValidator(this.descriptionIsRequired)(c);
  }
}

对正在发生的事情的一个小解释:

  • validator方法returns函数
  • validator 返回的函数可以被认为是一个 工厂方法:每当它被调用时,returns 一个新函数,更具体地说,一个新实例我们的 descriptionValidator 使用最新的 descriptionIsRequired 值。

现场演示如下stackblitz

也许这有帮助:

将 Validators.required 添加到现有 AbstractControl 的验证器集:

if (c.validator !== null) {
        c.setValidators([c.validator, Validators.required])
  } else {
        c.setValidators([Validators.required])
  }

这个对我有用

onAddValidationClick(){
    this.formGroup.controls["firstName"].setValidators(Validators.required);
    this.formGroup.controls["firstName"].updateValueAndValidity();
}

onRemoveValidationClick(){
    this.formGroup.controls["firstName"].clearValidators();
    this.formGroup.controls["firstName"].updateValueAndValidity();
}

任何仍在寻找答案的人,你可以这样做,在 ngOnInit() 或任何你喜欢的地方处理它。

   const validators = formGroup.validator; /* or control.validator */

   const newValidator = CustomValidator.checkUserNameValidity(); 

   /* Add to existing validator */

   if(validator) {
      formGroup.setValidators([validators, newValidator])
   } else {. /* if no validators added already */
      formGroup.setValidators([newValidator]);
   }

对 asyncValidator 也进行同样的操作。

如果您多次更改 "validator required"(例如,使用复选框),您应该添加:

this.formGroup.controls["firstName"].setErrors(null);

所以:

  onAddValidationClick(){
         this.formGroup.controls["firstName"].setValidators(Validators.required);
        this.formGroup.controls["firstName"].updateValueAndValidity();
      }

onRemoveValidationClick(){
         this.formGroup.controls["firstName"].setErrors(null);
         this.formGroup.controls["firstName"].clearValidators();
        this.formGroup.controls["firstName"].updateValueAndValidity();
      }

如果您多次更改 "validator required"(例如,使用复选框),您应该添加: 非常重要的领域! this.formGroup.controls["firstName"].setErrors(null);

我有一些表格,根据上下文需要一些值,但在其他表格中可以省略。在我的例子中,调用 'mainform.updateValueAndValidity()' 是不够的。当我动态设置需要验证时,我必须显式更新该字段:

formField.setValidators([RxwebValidators.required()]);
formField.updateValueAndValidity({onlySelf: true});

密钥是 {onlySelf: true}