Angular2表单自定义异步验证消抖

1,133 阅读2分钟

一、相关接口

就像同步验证器有 ValidatorFn 和 Validator 接口一样,异步验证器也有自己的对应接口:AsyncValidatorFn 和 AsyncValidator。

接口介绍及注意:

  • 它们必须返回Promise或可Observable对象
  • 返回的可观察对象必须是有限的,也就是说,它必须在某个时间点结束(complete)。要把无尽的可观察对象转换成有限的,可以使用 first、last、take 或 takeUntil 等过滤型管道对其进行处理。
  • 异步验证总是会在同步验证之后执行,并且只有当同步验证成功了之后才会执行。如果更基本的验证方法已经失败了,那么这能让表单避免进行可能会很昂贵的异步验证过程,比如 HTTP 请求。
  • 在异步验证器开始之后,表单控件会进入 pending 状态。(此时表单的valid和invalid状态均为false)

二、异步验证消抖

性能上的注意事项

默认情况下,每当表单值变化之后,都会执行所有验证器。对于同步验证器,没有什么会显著影响应用性能的地方。不过,异步验证器通常需要向后端发送请求(比如查询某个输入值是否在数据库已存在从而进行查重验证),因此我们需要消抖。

简单方法

把 updateOn 属性从 change(默认值)改成 submit 或 blur,进而在表单控件blur时才进行验证

this.validateForm = this.fb.group({
      userName: ['', [Validators.required]],
      email: ['', [Validators.email, Validators.required]],
    },{updateOn:'blur'});

但是在用户输入完长长的一段内容再blur之后才给他看验证结果,如果验证成功了还好,验证失败的话会影响交互体验

异步验证消抖

话不多说,先上代码

emailAsyncValidator():AsyncValidatorFn{
        //返回一个AsyncValidatorFn函数
        return (control:FormControl):Observable<ValidationErrors | null>=>{
            //返回一个Observable对象(注意几个rxjs操作符的处理)
            return control.valueChanges.pipe(debounceTime(300)).pipe(first()).pipe(switchMap(res=>
                Observable.create((observer: Observer<ValidationErrors>)=>{
                    this.apiService.post().subscribe(res=>{
                        if(res.json().data.length>0){
                            observer.next({ error: true, duplicated: true });
                        }else{
                            observer.next(null);
                        }
                        observer.complete()
                    })
                })
            ))
        }
    }