Angular - 动态添加/删除验证器

A J*_*shi 16 angular-validation angular angular-forms

我有一个FormGroup如下定义:

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

现在,当businessTypeOther,我想删除Validators.required的验证description.如果businessType不是Other,我想加回来Validators.required.

我使用以下代码动态添加/删除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(); 
Run Code Online (Sandbox Code Playgroud)

我的问题是,在添加/删除required验证器时如何保留现有的验证器.

Nar*_*arm 23

Angular表单具有内置函数setValidators(),可以对Validators进行编程分配.

对于您的示例,您可以:

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)]);               
}
Run Code Online (Sandbox Code Playgroud)

重要的是要记住,通过使用此方法,您将覆盖现有的验证器,因此您需要包含您正在重置的控件所需的所有验证器.

  • 请注意,setValidators将覆盖以前设置的验证器,这意味着将覆盖maxLength并且不会使用此方法重新生成 (2认同)
  • @Eliseo 您是对的,使用自定义验证器是更好的方法,但在我的情况下,我在 json 文件中定义了验证规则,我正在寻找更通用的实现,而 Narm 提供的解决方案可能是要走的路。 (2认同)
  • 对我来说,这只有在调用 updateValueAndValidity() 之后才有效,如链接文档中所建议的(使用 Angular 版本 8) (2认同)

小智 13

如果您多次更改“需要验证器”(例如,使用复选框),您应该添加以下内容:

this.formGroup.controls["firstName"].setErrors(null);
Run Code Online (Sandbox Code Playgroud)

所以:

  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();
      }
Run Code Online (Sandbox Code Playgroud)


San*_*isy 9

这个为我工作

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

onRemoveValidationClick(){
         this.formGroup.controls["firstName"].clearValidators();
        this.formGroup.controls["firstName"].updateValueAndValidity();
      }
Run Code Online (Sandbox Code Playgroud)


Jot*_*edo 6

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

考虑一个descriptionIsRequiredgetter的存在,它充当 boolan 标志。

想法:

  • 创建一个自定义验证器函数,该函数接受descriptionIsRequiredas 参数,并根据它根据 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);
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

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

第二点有点棘手,但最终看起来像这样:

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);
  }
}
Run Code Online (Sandbox Code Playgroud)

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

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

以下stackblitz中的实时演示