【问题标题】:Angular 4 remove required validator conditionallyAngular 4 有条件地删除所需的验证器
【发布时间】:2018-03-11 07:33:26
【问题描述】:

在 Angular 4 应用程序中,我有一个这样的表单模型:

this.form = this._fb.group({
    title: ['', [Validators.required, Validators.minLength(3), Validators.maxLength(50)]],
    description: ['', [Validators.required, Validators.minLength(3)]]
});

现在我想要的是从控件验证器数组中动态删除所需的验证器。像这样的:

saveDraft() {
    this.form.controls['title'].removeValidator('required'); //Just a fake implementation for demonstration
}

这个问题不是上述问题的重复。我的情况不同,我只是想在不知情的情况下删除所需的验证器。

【问题讨论】:

标签: forms angular validation typescript


【解决方案1】:

你可以使用:AbstractControl.removeValidators(validator: ValidatorFn)

不确定在 Angular 4 中是否可行,但肯定在 Angular 12 及更高版本中。

但是,它需要对exact same function 的引用。 仅仅给它 Validators.required 是行不通的。您需要为它创建一个唯一的引用:

requiredValidator = Validators.required;
   
this.form = this._fb.group({
    title: ['', [this.requiredValidator, Validators.minLength(3), Validators.maxLength(50)]],
    description: ['', [this.requiredValidator, Validators.minLength(3)]]
}); 

saveDraft() {
    this.title.removeValidator(this.requiredValidator); 
}

get title(): AbstractControl {
    return this.form.get('title');
}

【讨论】:

    【解决方案2】:

    我们可以使用setValidators 来移除验证。

    setValidators(newValidator: ValidatorFn | ValidatorFn[]): void
    

    setValidators() - setValidators 以编程方式添加同步验证器。此方法将删除所有之前添加的同步或异步验证器。

    this.form.get('title').setValidators(null); 
    this.form.get('title').setErrors(null); 
    

    【讨论】:

    • 它对我有用。当项的值为空时,它使表单有效。
    【解决方案3】:
    this.fromName.get("formControlName").setValidators([Validators.required]);//setting validation
    this.fromName.get("formControlName").setErrors({'required':true});//error message
    this.fromName.updateValueAndValidity();//update validation
    
    
    this.fromName.get("formControlName").clearValidators([Validators.required]);//clear validation
    this.fromName.get("formControlName").setErrors(null);//updating error message
    this.fromName.updateValueAndValidity();//update validation
    

    【讨论】:

    • 虽然此代码可能会为问题提供解决方案,但最好添加有关其工作原理/方式的上下文。这可以帮助未来的用户学习并将这些知识应用到他们自己的代码中。在解释代码时,您也可能会以赞成票的形式从用户那里获得积极的反馈。
    • clearValidators() 不接受参数,并清除所有验证器。见angular.io/api/forms/AbstractControl#clearValidators
    • clearValidators() 上没有参数。为什么人们投票给这个错误的信息..!!!
    【解决方案4】:

    您可以使用它来清除响应式表单中的验证

    this.form.controls['title'].clearValidators(); this.form.controls['title'].updateValueAndValidity();

    您可以使用它以反应形式添加验证

    this.form.controls['title'].setValidators([Validators.required]); this.form.controls['title'].updateValueAndValidity();

    【讨论】:

      【解决方案5】:

      使用空数组删除所有现有的验证器。

      this.frmFeasibility.controls['pop_name'].setValidators([]);
      this.frmFeasibility.controls['pop_name'].updateValueAndValidity();
      

      【讨论】:

        【解决方案6】:

        添加验证器:

        this.form = this._fb.group({
            title: ['', [Validators.required, Validators.minLength(3), Validators.maxLength(50)]],
            description: ['', [Validators.required, Validators.minLength(3)]]
        });
        

        或

        this.form.get('title').setValidators([Validators.required,Validators.minLength(3), Validators.maxLength(50)]);

        要仅删除“必需”验证器,您可以重置验证器。

        saveDraft() {
             this.form.get('title').setValidators([Validators.minLength(3), Validators.maxLength(50)]);
             this.form.get('title').updateValueAndValidity();
        }
        

        updateValueAndValidity 确定控件如何传播更改并在值和验证器更改时发出事件

        【讨论】:

          【解决方案7】:

          我不喜欢清除和设置验证器,因为我必须重复所有静态验证器(模式、最小值、最大值等)才能拥有一个动态的“必需”验证器。

          我使用条件验证器:

          export function conditionalValidator(condFn: (control: AbstractControl) => boolean,
          validators: ValidatorFn | ValidatorFn[]): ValidatorFn {
            return (control) => {
              if (!condFn(control)) {
                return null;
              }
          
              if (!Array.isArray(validators)) {
                return validators(control);
              }
          
              return validators.map(v => v(control)).reduce((errors, result) =>
                result === null ? errors :
                  (Object.assign(errors || {}, result))
              );
            };
          }
          

          然后我可以将静态验证器与动态“必需”条件混合:

          this.fb.group({name: ['', [Validators.minLength(4),
                           conditionalValidator(this.isClientProj, Validators.required)]]}
          

          其中isClientProj()是条件函数(闭包)

          【讨论】:

          • 我认为这里需要注意的是,需要做一些事情来确保条件值的变化会触发重新验证。我认为复选框的更改不会触发其他表单字段的验证。
          • 对,这就是我目前正在尝试解决的问题。如果您处于无效状态并且验证器条件更改为 false,则表单仍然无效,除非您手动启动不太理想的验证周期。 Validator 接口确实定义了一个 changed 事件钩子,据我所知,它是 Angular 钩子再次触发验证的原因,所以我要尝试一下。
          【解决方案8】:

          我在将条目保存为草稿时遇到了同样的问题,并准备了以下解决方案:

          @Component({
              // ...
          })
          export class FormComponent{
              form: FormGroup;
          
              constructor(private fb: FormBuilder){
                  this.form = this.fb.group({
                      name: ['', Validators.required, Validators.maxLength(20)],
                      description: ['', Validators.required, Validators.maxLength(200)],
                      address: this.fb.group({
                          line1: ['', Validators.required, Validators.maxLength(100)],
                          line2: ['', Validators.maxLength(100)]
                      })
                  });
              }    
          
              validateDraft(formElement: FormGroup | FormArray | FormControl): boolean {
                  let result = true;
          
                  Object.keys(formElement.controls).forEach(field => {
                      const control = formElement.get(field);
          
                      if(control instanceof FormControl) {
                          control.markAsTouched({ onlySelf: true });
          
                          if(control.errors && control.errors['required']) {
                              control.markAsUntouched({ onlySelf: true });
                          }
                          else if(control.invalid) {
                              result = false;
                          }
                      } else if (control instanceof FormArray) {
                          if (!this.validateDraft(control)) {
                              result = false;
                          } 
                      }else if (control instanceof FormGroup) {
                          if (!this.validateDraft(control)) {
                              result = false;
                          }   
                      }
                  });
              }
          
              saveDraft(){
                  if(this.validateDraft(this.form)){
                      //save draft - ignore required errors
                  }
              }
          
              save(){
                  if(this.form.valid){
                      //save
                  }
              }
          }
          

          【讨论】:

          • 这对我来说是最好的解决方案
          【解决方案9】:

          不幸的是,Angular 目前还没有 removeValidator 功能。您所能做的就是重新设置验证器,而不是要删除的验证器,因此您需要知道要保留哪些验证器,而不是要删除的验证器。所以这个:

          this.form.get('title').setValidators([Validators.minLength(3), Validators.maxLength(50)]);
          

          是最接近删除功能的方法。您也无法访问表单控件上的当前验证器来尝试编写自己的删除函数。您能做的最好的事情就是编写自己的表单控件验证管理器类,该类可以跟踪给定控件上的验证器并为您管理它们。

          【讨论】:

          • 我在这里是因为我设置了 min/maxlength 的控件在空字段上仍然出现 required 错误。
          【解决方案10】:

          如果你想添加验证,试试这个。

          saveDraft() {
             this.form.get('title').setValidators([Validators.required, Validators.minLength(3)]);
             this.form.get('title').updateValueAndValidity();
          }
          

          如果你想删除验证器,试试这个。

          saveDraft() {
           this.form.get('title').clearValidators();
           this.form.get('title').updateValueAndValidity();
          }
          

          【讨论】:

          • 这对我不起作用。在我的情况下,我有更改事件的下拉菜单,我正在调用一个函数来设置验证器,如上所述。任何可能有问题的建议。
          • @Zaker 请使用您的代码发布一个新问题,并链接到该问题。
          • 对于遇到此问题的其他人,我必须执行 this.form.get('title').setValidators(null); this.form.get('title').setErrors(null) 以确保 this.form.valid = true
          • @CalebSwank 感谢您添加此内容。 setErrors(null) 和 setValidators(null); 工作得很好。 :-)
          • 但是当您再次添加所需的验证器时删除错误后,您需要添加错误:(.
          猜你喜欢
          • 1970-01-01
          • 2019-03-26
          • 2020-04-27
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-08-27
          • 2018-08-28
          • 2018-01-02
          相关资源
          最近更新 更多