繁体   English   中英

如何在自定义 ControlValueAccessor 中使用内置 Angular 验证器

[英]How to use Built-in Angular validator within custom ControlValueAccessor

我的应用程序上有一个继承 ControlValueAccessor 的自定义组件,它集成了ng-select

该组件的目标是将 ng-select 集成到一个中心位置,以便我可以在整个应用程序中重复使用它。

这就是我调用验证方法的方式:

  constructor(
    @Optional() @Self() public controlDir: NgControl
  ) {
    controlDir.valueAccessor = this;
  }

  ngOnInit() {
    const control = this.controlDir.control;
    if (control.validator) {
      control.setValidators([this.validate.bind(this, [control.validator])]);
    }
    control.updateValueAndValidity({ emitEvent: false });
  }

  validate(validators: ValidatorFn[], c: FormControl) {
    const allErrors: any = {};
    for (const validator of validators) {
      const hasError = validator(c);
      if (hasError) {
        Object.entries(hasError).forEach(([errorName, isOnError]) => {
          allErrors[errorName] = isOnError;
        });
      }
    }

    if (Object.keys(allErrors).length > 0) {
      return allErrors;
    }

    return null;
  }

这就是我通常在父组件上实例化 formControl 的方式:

const control = this.formBuilder.control(['test@gmail.com'], [Validators.email]);

this.form = this.formBuilder.group({ test: control });

我想让家长可以选择在我的自定义组件上使用内置 angular 验证器。 (必填,email,最小值,最大值...)。

问题是我的自定义组件的控件值是一个字符串数组,例如该值将是:

[ 'test@gmail.com', 'jeff@gmail.com' ]

该组件看起来像这样

组件截图

问题:在我的验证 function 中,我可以访问 ValidatorFn,它将检查我的控件是否有效 email。如果我的控件值是一个字符串,它会按预期工作,但它是一个字符串数组,所以它不工作。

所以我的猜测是我需要为我的自定义组件重新实现 email 验证器(因为 angular 无法神奇地找出我的自定义组件中的数据结构是有道理的)。

但我不知道如何识别定义的验证器是Validator.email

this.controlDir.control.validator是一个 function,我不知道如何识别它是 email 验证器,因此我可以为电子邮件添加自定义验证。

问题:我如何从我的自定义验证 function 知道哪个验证器是从父级设置的? 是Validators.required, Validators.email...等等

我如何从我的自定义验证 function 知道哪个验证器是从父级设置的? 是不是Validators.required, Validators.email

每个验证器 function 都会返回一个错误 object。如果您从angular看到 Validators.email(),它会返回{ 'email': true } object。因此,如果您遍历control.errors (或您的示例中的hasError ),您可以检查如果任何 object 的密钥匹配email -

static email(control) {
        if (isEmptyInputValue(control.value)) {
            return null; // don't validate empty values to allow optional controls
        }
        return EMAIL_REGEXP.test(control.value) ? null : { 'email': true };
    }

以下是您的validate() function 的样子 -

validate(validators: ValidatorFn[], c: FormControl) {
    const allErrors: any = {};
    for (const validator of validators) {
      const hasError = validator(c);
      if (hasError) {
        Object.entries(hasError).forEach(([errorName, isOnError]) => {
          if(errorName === 'email' ) {
            console.log('Validators.email was set');
          }
          allErrors[errorName] = isOnError;
        });
      }
    }

    if (Object.keys(allErrors).length > 0) {
      return allErrors;
    }

    return null;
  }

我如何从我的自定义验证 function 知道哪个验证器是从父级设置的?

不幸的是,没有办法获得给定控件的验证器(详细信息)。

理论上,您可以遍历控件值(如果它是一个数组)并创建一个新的FormControl来验证数组中的每个字符串。

例如,您可以这样做:

isControlValid(controlValue: string[], validator: ValidatorFn) {
  let emailHasError = false;
  for (value of controlValue) {
    const ctrl = new FormControl(value, validator);
    if (Object.keys(validator(ctrl)).length) {
      emailHasError = true; // if any of the values are invalid
    }
  }
  return emailHasError; // or return whatever you need to.
}

也许像这样使用它

validate(validators: ValidatorFn[], c: FormControl) {
  const allErrors: any = {};
  for (const validator of validators) {
    if (Array.isArray(c.value)) {
      if (this.isControlValid(c.value, validator)) {
        // maybe update `allErrors` here or something

您可以根据需要实现它,但其想法只是使用它自己的表单控件来验证每个字符串。

可能有一些晦涩的方法可以使用NG_VALIDATORS以不同的方式实现这一点,但我没有研究过。

暂无
暂无

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

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