如何让自定义AsyncValidatorFn仅在用户完成输入后触发执行
解决方案
方案1:仅失焦时触发校验(完全匹配你要的Validators.required触发逻辑)
这是最适配你需求的方案,只需修改组件内表单控件的更新时机配置即可,不需要改动其他代码:
改造后的表单组配置:
email: ["", { validators: [Validators.required, Validators.email], asyncValidators: EmailUniqueValidator.createValidator(this.usersService), updateOn: 'blur' }]
配置后该控件的所有同步、异步校验器只会在输入框失焦时才触发,完全符合你要的「用户点击输入框后失焦才校验」的效果,不会在输入过程中每输入一个字符就发请求。
方案2:输入过程中防抖触发(停止输入后再发请求)
如果你需要边输入边校验但不想频繁发请求,可以在异步校验器中加入防抖逻辑,改造校验器类代码即可:
首先导入所需RxJS操作符:
import { debounceTime, distinctUntilChanged, switchMap, of } from 'rxjs';
改造后的校验器代码:
export class EmailUniqueValidator{ static createValidator(usersService:UsersService):AsyncValidatorFn{ return(control: AbstractControl): Observable<ValidationErrors> =>{ // 先判断值是否合法,格式不对/空值直接不发请求 if (!control.value || control.hasError('email')) { return of(null); } return of(control.value).pipe( debounceTime(300), // 停止输入300ms后才往下执行,时长可自定义 distinctUntilChanged(), // 和上一次输入值相同则不重复发请求 switchMap(email => usersService.checkEmail(email)), // 用switchMap自动取消前一次未完成的无效请求 map((result:boolean) => result ? null: {emailUsed:true}) ) } } }
补充优化建议
你可以在用户服务的checkEmail方法里再加一层空值判断,避免发送无意义的请求:
checkEmail(email:string){ // 空值直接返回不合法,不用发请求 if (!email) return of(false); const data={email:email} const url = `${this.baseUrl}${ApiPaths.User}/checkEmail` return this.http.post(url,data).pipe(map((result)=>result["message"]=="email ok"?true:false)) }
内容的提问来源于stack exchange,提问作者kljaja998
相关产品推荐
相关产品推荐

