Angular高级教程:构建可配置的自定义表单验证器
在Angular表单开发中,自定义验证器是扩展表单验证功能的强大工具。本文将深入探讨如何在Angular中创建可配置的自定义验证器,适用于模型驱动表单和模板驱动表单两种场景。
为什么需要可配置验证器
在真实项目中,我们经常遇到需要复用验证逻辑但验证条件可能变化的情况。例如,一个邮箱验证器可能需要验证不同的域名,而不是固定的某个域名。这就是可配置验证器的用武之地。
模型驱动表单的可配置验证器
验证器工厂函数
我们可以通过工厂函数模式创建可配置的验证器:
function emailDomainValidatorFactory(requiredDomain: string) {
return function (control: FormControl) {
const email = control.value;
if (email && email.includes("@")) {
const [_, domain] = email.split("@");
if (domain !== requiredDomain) {
return {
emailDomain: {
valid: false,
parsedDomain: domain,
requiredDomain: requiredDomain
}
};
}
}
return null;
};
}
这个工厂函数接受一个requiredDomain
参数,返回一个配置好的验证器函数。
使用验证器
在模型驱动表单中使用这个验证器:
this.email = new FormControl('', [
Validators.required,
Validators.pattern("[^ @]*@[^ @]*"),
emailDomainValidatorFactory('codecraft.tv')
]);
封装为验证器类
为了更好的组织代码,我们可以将验证器封装为静态类:
class CodeCraftValidators {
static emailDomain(requiredDomain: string) {
return function (control: FormControl) {
// 验证逻辑同上
};
}
}
使用方式变为:
CodeCraftValidators.emailDomain('codecraft.tv')
模板驱动表单的可配置验证器
模板驱动表单的可配置验证器实现更为复杂,需要结合Angular的依赖注入系统。
通过依赖注入配置
- 首先在NgModule中提供配置值:
@NgModule({
providers: [
{provide: 'RequiredDomain', useValue: 'codecraft.tv'}
]
})
- 创建验证器指令类:
@Directive({
selector: '[emailDomain][ngModel]',
providers: [
{
provide: NG_VALIDATORS,
useClass: EmailDomainValidator,
multi: true
}
]
})
class EmailDomainValidator implements Validator {
private valFn: ValidatorFn;
constructor(@Inject('RequiredDomain') requiredDomain: string) {
this.valFn = CodeCraftValidators.emailDomain(requiredDomain);
}
validate(control: FormControl) {
return this.valFn(control);
}
}
通过输入属性配置
更灵活的方式是通过输入属性动态配置验证器:
@Directive({
selector: '[emailDomain][ngModel]',
providers: [
{
provide: NG_VALIDATORS,
useExisting: forwardRef(() => EmailDomainValidator),
multi: true
}
]
})
class EmailDomainValidator implements Validator, OnChanges {
@Input('emailDomain') emailDomain: string;
private valFn: ValidatorFn = Validators.nullValidator;
ngOnChanges() {
if (this.emailDomain) {
this.valFn = CodeCraftValidators.emailDomain(this.emailDomain);
} else {
this.valFn = Validators.nullValidator;
}
}
validate(control: FormControl) {
return this.valFn(control);
}
}
在模板中使用:
<input type="email"
[(ngModel)]="model.email"
[emailDomain]="'example.com'">
验证错误信息处理
为了使错误信息也能动态显示配置的域名,我们需要在验证器返回的错误对象中包含这些信息:
return {
emailDomain: {
parsedDomain: domain,
requiredDomain: requiredDomain
}
};
然后在模板中:
<p *ngIf="email.errors?.emailDomain">
邮箱必须使用 {{ email.errors.emailDomain.requiredDomain }} 域名
</p>
最佳实践总结
- 复用验证逻辑:无论是模型驱动还是模板驱动表单,都可以共享同一个验证器工厂函数
- 灵活配置:根据场景选择依赖注入或输入属性进行配置
- 错误信息动态化:在错误对象中包含配置信息,使UI反馈更加灵活
- 类型安全:为验证器函数和配置参数添加正确的TypeScript类型注解
通过可配置的自定义验证器,我们可以创建更加灵活、可复用的表单验证逻辑,大大提高开发效率和代码质量。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考