如何在Angular响应式表单中正确添加异步验证器
Angular 13 响应式表单异步验证配置问题
我在Angular 13应用中参照官方指南尝试实现异步验证功能,具体实现代码如下:
check-current-password.validator.ts 代码
@Injectable({ providedIn: 'root' }) export class CheckCurrentPasswordValidator implements AsyncValidator { constructor(private userService: UserService) {} validate( control: AbstractControl ): Promise<ValidationErrors | null> | Observable<ValidationErrors | null> { return this.userService.verifyMatchWithCurrentPassword(control.value).pipe( map((value) => (value ? null : { passwordMatch: true })), catchError(() => of(null)) ); } }
user.service.ts 代码
@Injectable({ providedIn: 'root', }) export class UserService { constructor() {} verifyMatchWithCurrentPassword(password: string): Observable<boolean> { return of(password === 'password').pipe(delay(5000)); } }
我尝试按如下方式把异步验证器添加到表单中:
editPasswordForm: FormGroup = this.formBuilder.group( { currentPassword: [ '', [ Validators.required, this.checkCurrentPasswordValidator.validate(), // <-- async validation ], ], newPassword: ['', Validators.required], repeatNewPassword: ['', Validators.required], }, { validators: newPasswordMatchValidator } );
调用validate方法时收到如下报错:
TS2554: Expected 1 arguments, but got 0.
check-current-password.validator.ts(15, 5): An argument for 'control' was not provided
请问如何才能正确为响应式表单添加异步验证?
问题解答
错误原因
你当前的写法存在两个核心问题:
- 不能手动调用
validate()方法:该方法需要的AbstractControl类型参数会由Angular内部自动传入,只需要传入验证器本身即可。 - 同步、异步验证器配置混淆:
FormControl的配置中,同步验证器和异步验证器是独立的配置项,不能把异步验证器放到同步验证器的数组中。
两种正确实现方案
方案1:直接使用已实现的AsyncValidator类
你已经实现了实现AsyncValidator接口的验证器类,直接把注入后的实例放到asyncValidators配置数组即可:
editPasswordForm: FormGroup = this.formBuilder.group( { currentPassword: [ '', { validators: [Validators.required], asyncValidators: [this.checkCurrentPasswordValidator], updateOn: 'blur' // 推荐配置为失焦时触发,减少不必要的验证请求 } ], newPassword: ['', Validators.required], repeatNewPassword: ['', Validators.required], }, { validators: newPasswordMatchValidator } );
方案2:使用AsyncValidatorFn工厂方法
这种写法不需要单独实现验证器类,逻辑更轻便:
首先在user.service.ts中新增验证器工厂方法:
passwordValidator(): AsyncValidatorFn { return (control: AbstractControl): Observable<ValidationErrors | null> => { return this.verifyMatchWithCurrentPassword(control.value).pipe( map((value) => (value ? null : { passwordMatch: true })) ); }; }
再按如下方式配置表单即可正常运行:
editPasswordForm: FormGroup = this.formBuilder.group( { currentPassword: [ '', { validators: [Validators.required], asyncValidators: [this.userService.passwordValidator()], updateOn: 'blur', }, ], newPassword: ['', Validators.required], repeatNewPassword: ['', Validators.required], }, { validators: newPasswordMatchValidator } );
内容的提问来源于stack exchange,提问作者Mario
相关产品推荐
相关产品推荐

