繁体   English   中英

Angular Reactive Forms 中的自定义验证器不起作用

[英]Custom Validator in Angular Reactive Forms not working

我在字段postalCode上有一个自定义验证器:

function postalCodeValidator(): ValidatorFn {
  return (control: AbstractControl): ValidationErrors | null => {
    if (!this.contactForm) {
      return null;
    }

    const isPotalCodeRequired = this.contactForm.get(
      'isPotalCodeRequired'
    ).value;

    if (isPotalCodeRequired && !control.value) {
      console.log('here');
      this.contactForm.controls['postalCode'].setErrors({ required: true });
    } else {
      this.contactForm.controls['postalCode'].setErrors({ required: false });
    }

    return null;
  };
}

它检查另一个字段isPotalCodeRequired以查看是否应将验证应用于postalCode字段。

如果isPotalCodeRequired为真,则postalCode需要一个值,否则它可以留空。 但是当我在postalCode字段上调用setErrors时,我的自定义验证似乎没有按预期工作。 它在自定义验证器函数中添加它,但在函数执行后检查它, postalCode字段上不再存在错误。

演示

Angular 的验证器函数有点奇怪。 当控件没有错误时,您需要返回null并且包含错​​误的对象以及错误时的简要说明:

function postalCodeValidator(): ValidatorFn {
  return (control: AbstractControl): ValidationErrors | null => {
    if (!this.contactForm) {
      return null;
    }

    const isPotalCodeRequired = this.contactForm.get(
      'isPotalCodeRequired'
    ).value;

    if (isPotalCodeRequired && !control.value) {
      console.log('here');
      return {required: 'Postal code is required' };
    }

    return null;
  };
}

您无需手动设置错误,因为框架会为您完成

您正在尝试做的事情称为跨字段验证,通常使用跨字段验证器,您应该将验证器应用到FormGroup而不是FormControl 这里,

this.contactForm = this.formBuilder.group({
  isPotalCodeRequired: [true],
  postalCode: [null, Validators.compose([postalCodeValidator.call(this)])],
});

您正在将您的 postalCodeValidator 绑定到特定控件。 当您应用这样的验证器时,该验证器应返回您希望应用于控件但您返回 null 的验证消息,

  if (isPotalCodeRequired && !control.value) {
    console.log('here');
    this.contactForm.controls['postalCode'].setErrors({ required: true });
  } else {
    this.contactForm.controls['postalCode'].setErrors({ required: false });
  }

  return null;

这将清除应用于该控件的所有验证消息。 相反,将此验证器绑定到包含两个控件的FormGroup

this.contactForm = this.formBuilder.group({
  isPotalCodeRequired: [true],
  postalCode: [null]
}, {validators: Validators.compose([postalCodeValidator.call(this)])});

现在,传递给验证器的 AbstractControl 就是您的整个 FormGroup。 这样做的好处是可以访问您需要的所有控件。 因此,您将拥有的不是对this.contactForm的引用,

control.controls['postalCode'].setErrors({ required: true });

您应该能够从验证器内部删除对this.contactForm的所有引用。 更重要的是,您的 null 返回将不再清除单个控件上的验证消息。 查看有关响应式表单的跨字段验证的Angular 文档

但是有一种更清洁的方法可以完全做到这一点。 无需编写自定义验证器,您只需侦听 isPostalCodeRequired 上的更改并根据需要添加/删除内置的所需验证器,

this.contactForm.get('isPostalCodeRequired').valueChanges.subscribe(val => {
  if (val) { 
    //Add validator
  else {
    //Remove validator
  })

可用于添加/删除验证器的辅助函数取决于您的 Angular 版本,但它们非常简单。

编辑:更新了答案以解决演示中的代码。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM