Angular 角度-动态添加/删除验证程序

Angular 角度-动态添加/删除验证程序,angular,angular-forms,angular-validation,Angular,Angular Forms,Angular Validation,我有一个FormGroup定义如下: this.businessFormGroup: this.fb.group({ 'businessType': ['', Validators.required], 'description': ['', Validators.compose([Validators.required, Validators.maxLength(200)])], 'income': [''] }) 现在,当businessType为Other时,

我有一个
FormGroup
定义如下:

this.businessFormGroup: this.fb.group({
    'businessType': ['', Validators.required],
    'description': ['', Validators.compose([Validators.required, Validators.maxLength(200)])],
    'income': ['']
  })
现在,当
businessType
Other
时,我想从
description
中删除
验证器。必需的
验证器。如果
businessType
不是
Other
,我想重新添加
验证器

我正在使用下面的代码动态添加/删除
验证器。必需
。但是,它会清除现有的
验证器.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(); 
if(this.businessFormGroup.get('businessType').value!=='Other'){
this.businessFormGroup.get('description').validator=Validators.compose([Validators.required]);
}否则{
this.businessFormGroup.get('description').clearValidators();
}
this.businessFormGroup.get('description').updateValueAndValidity();

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

Angular forms有一个内置函数,可以通过编程方式分配验证器

例如,您可以执行以下操作:

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();

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

最简单的方法是在条件变量更改时设置控件的验证器。但是,通过使用一些间接+函数式编程,我们实际上可以做得更好

考虑存在一个
描述所需的
getter,它充当boolan标志

想法:

  • 创建一个自定义验证器函数,该函数将
    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
    方法返回一个函数
  • validator
    返回的函数可以看作是一个工厂方法:无论何时调用它,都会返回一个新函数,更具体地说,就是使用最新的
    descriptionsrequired
    值返回我们的
    descriptionValidator
    的一个新实例
下面的现场演示可能会有所帮助:

将Validators.required添加到现有
抽象控件的validatorset

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的相同操作。

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

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

如果您多次更改“需要验证程序”(例如,使用复选框),则应添加以下内容: 非常重要的领域!
this.formGroup.controls[“firstName”].setErrors(null)

验证器像一个数组一样存储,您需要处理自己应用的验证器列表。遗憾的是,这是不可能的,angular似乎会在内部合并应用的验证器,因此您只能调用
clear
set
functions@Ricardo那是错误的,验证器由一个函数组成,就是这样。在当前的API实现中,无法检查为控件设置了哪些验证器请注意,setValidators将覆盖以前设置的验证器,这意味着maxLength将被覆盖,并且不会使用此方法重新生成谢谢@Jota.Toledo。这是一个需要注意的重要行为。更新了答案以包含它。我认为使用考虑了业务类型和描述的customValidator是“更自然的”删除/添加的想法validators@Eliseo您是对的,拥有一个自定义验证器是更好的方法,但在我的例子中,我在json文件中定义了验证规则,我正在寻找一个更通用的实现,Narm提供的解决方案可能是最好的选择。对我来说,这只在之后调用updateValueAndValidity()后才起作用,正如链接文档(使用Angular version 8)+1中所建议的那样,这是一个有效的解决方案,但我正在寻找一个更通用的实现,因为我的验证规则是在json文件中定义的。我想知道在这种情况下,泛型是什么意思。我所看到的将其推广的唯一方法是,您有一组验证器
V
,这些验证器必须在控件中始终处于活动状态。他们从哪里来无关紧要。然后您有另一个验证器集合
Vop
,在本例中,该集合中仅包含必需项,根据布尔条件,该集合可以在控件中处于活动状态,也可以不处于活动状态。我说得对吗?如果没有,请进一步解释“更通用”实现的概念。干杯!这让我有了一个好主意,可以做一些我需要做的一般性工作,比如处理setErrors(null);。但是updateValueAndValidity({onlySelf:true});它不起作用。
  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();
      }