如何在自定义 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 验证器。 (必填,电子邮件,最小值,最大值...)。
问题是我的自定义组件的控件值是一个字符串数组,例如值将是:
[ 'test@gmail.com', 'jeff@gmail.com' ]
组件看起来像这样
问题:在我的验证函数中,我可以访问 ValidatorFn,它会检查我的控件是否是有效的电子邮件。如果我的控制值是一个字符串,它会按预期工作,但它是一个字符串数组,所以它不起作用。
所以我的猜测是我需要为我的自定义组件重新实现电子邮件验证器(因为 angular 无法神奇地找出我的自定义组件中的数据结构是有道理的) .
但我不知道如何识别定义的验证器是Validator.email
。
this.controlDir.control.validator
是一个函数,我不知道如何识别它是电子邮件验证器,因此我可以为电子邮件添加自定义验证。
问题:我如何从我的自定义验证函数中知道哪个验证器是从父级设置的?是 Validators.required、Validators.email ...等等
How can I know from my custom validate function which Validator was
set from the parent? Was it Validators.required, Validators.email
每个验证器函数 returns 一个错误对象。如果您从 angular
看到 Validators.email(),它是 returns { 'email': true }
对象。因此,如果您遍历 control.errors
(或您的示例中的 hasError
),您可以检查任何对象的键是否匹配 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()
函数的样子 -
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;
}
How can I know from my custom validate function which Validator was
set from the parent?
遗憾的是,无法获取给定控件 (details) 的验证器。
理论上,您可以迭代控制值(如果它是一个数组)并创建一个新的 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
可能有一些晦涩的方法可以不同地实现这一点,但我没有研究过。
我的应用程序上有一个继承 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 验证器。 (必填,电子邮件,最小值,最大值...)。
问题是我的自定义组件的控件值是一个字符串数组,例如值将是:
[ 'test@gmail.com', 'jeff@gmail.com' ]
组件看起来像这样
问题:在我的验证函数中,我可以访问 ValidatorFn,它会检查我的控件是否是有效的电子邮件。如果我的控制值是一个字符串,它会按预期工作,但它是一个字符串数组,所以它不起作用。
所以我的猜测是我需要为我的自定义组件重新实现电子邮件验证器(因为 angular 无法神奇地找出我的自定义组件中的数据结构是有道理的) .
但我不知道如何识别定义的验证器是Validator.email
。
this.controlDir.control.validator
是一个函数,我不知道如何识别它是电子邮件验证器,因此我可以为电子邮件添加自定义验证。
问题:我如何从我的自定义验证函数中知道哪个验证器是从父级设置的?是 Validators.required、Validators.email ...等等
How can I know from my custom validate function which Validator was set from the parent? Was it Validators.required, Validators.email
每个验证器函数 returns 一个错误对象。如果您从 angular
看到 Validators.email(),它是 returns { 'email': true }
对象。因此,如果您遍历 control.errors
(或您的示例中的 hasError
),您可以检查任何对象的键是否匹配 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()
函数的样子 -
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;
}
How can I know from my custom validate function which Validator was set from the parent?
遗憾的是,无法获取给定控件 (details) 的验证器。
理论上,您可以迭代控制值(如果它是一个数组)并创建一个新的 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
可能有一些晦涩的方法可以不同地实现这一点,但我没有研究过。