Angular 响应式表单中的自定义验证器无法正常工作
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
字段中。
Demo.
您尝试做的是所谓的 cross-field 验证,通常使用 cross-field 验证器,您应该将验证器应用到 FormGroup
而不是 FormControl
.这里,
this.contactForm = this.formBuilder.group({
isPotalCodeRequired: [true],
postalCode: [null, Validators.compose([postalCodeValidator.call(this)])],
});
您正在将 postalCodeValidator 绑定到特定控件。当您应用这样的验证器时,该验证器应该 return 您想要应用到控件的验证消息,但您 returning 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 return 将不再清除单个控件上的验证消息。查看 Angular docs 上的 cross-field 反应式表单验证。
但是有一种更简洁的方法可以完全做到这一点。无需编写自定义验证器,您只需监听 isPostalCodeRequired 和 add/remove 所需的 built-in 所需验证器的更改,
this.contactForm.get('isPostalCodeRequired').valueChanges.subscribe(val => {
if (val) {
//Add validator
else {
//Remove validator
})
add/remove 验证器可用的辅助函数取决于您的 Angular 版本,但它们非常简单。
编辑:更新了解决演示中代码的答案。
Angular 的验证函数有点奇怪。当控件没有错误时,您需要 return 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;
};
}
您无需手动设置错误,因为框架会为您完成
我在字段上有一个自定义验证器 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
字段中。
Demo.
您尝试做的是所谓的 cross-field 验证,通常使用 cross-field 验证器,您应该将验证器应用到 FormGroup
而不是 FormControl
.这里,
this.contactForm = this.formBuilder.group({
isPotalCodeRequired: [true],
postalCode: [null, Validators.compose([postalCodeValidator.call(this)])],
});
您正在将 postalCodeValidator 绑定到特定控件。当您应用这样的验证器时,该验证器应该 return 您想要应用到控件的验证消息,但您 returning 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 return 将不再清除单个控件上的验证消息。查看 Angular docs 上的 cross-field 反应式表单验证。
但是有一种更简洁的方法可以完全做到这一点。无需编写自定义验证器,您只需监听 isPostalCodeRequired 和 add/remove 所需的 built-in 所需验证器的更改,
this.contactForm.get('isPostalCodeRequired').valueChanges.subscribe(val => {
if (val) {
//Add validator
else {
//Remove validator
})
add/remove 验证器可用的辅助函数取决于您的 Angular 版本,但它们非常简单。
编辑:更新了解决演示中代码的答案。
Angular 的验证函数有点奇怪。当控件没有错误时,您需要 return 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;
};
}
您无需手动设置错误,因为框架会为您完成