ng2 响应式表单 blur的时候更新

一直在使用angular的响应式表单来写业务,得心应手很是方便。但忽然领导反应说表单在刚开始输入的时候就会去验证,还没输完呢就出来一大坨红色的错误信息,很是不爽,感觉不是很好的用户体验,需要改为当用户输入完成后再验证,也就是当输入框遗失焦点(blur)之后才进行验证。得,找找解决方案吧。

先看看我们的表单结构:

1
2
3
 this.validateForm = this.fb.group({
code: [null, [Validators.required, this.onlyNumber(), Validators.minLength(2), Validators.maxLength(6)]],
});

我们是使用FormBuilder快速创建表单的,配置的时候就赋予对应的验证器。

第一种方法:动态移除和添加验证器

这是个比较简单的方法,竟然是要在鼠标遗失的时候显示错误信息,那么我们使鼠标遗失的时候添加验证器进行判断,在鼠标进入的时候移除验证器,这样不是就可以么?

我们写出对应的方法:

1
2
3
4
5
6
7
8
9
// 鼠标遗失
formBlur() {
this.loginForm.controls['email'].setValidators([Validators.required, Validators.minLength(4)]);
this.loginForm.controls['email'].updateValueAndValidity();
}
// 鼠标进入
formFocus() {
this.loginForm.controls['email'].clearValidators();
}

这样看起来是可以的,但是仔细一想,行不通啊,表单字段少还可以勉强接受,但是字段一多,验证器也各种各样,而且要绑定在表单html元素上,挨个绑定,烦不胜烦。不能这样搞。

第二种:通过配置修改表单验证时间

我们使用FormBuilder创建的表单,而FormBuilder是快速创建FormGroup的一个方式。那归根结底,我们创建的是FormGroup,那FormGroup有没有提供一些配置达到我们的需求?

看看FormGroup的介绍:,可以发现构造函数中传递的第二个参数validatorOrOpts有一个类型AbstractControlOptions。看看这个AbstractControlOptions里面的内容。

这个是AbstractControlOptions是定义的一个接口:

1
2
3
4
5
interface AbstractControlOptions {
validators?: ValidatorFn | ValidatorFn[] | null
asyncValidators?: AsyncValidatorFn | AsyncValidatorFn[] | null
updateOn?: 'change' | 'blur' | 'submit'
}

定义了三个成员:

  • validators 同步验证器
  • asyncValidators 异步验证器
  • updateOn 更新控件的事件名称

看来我们找到了,这里这个updateOn才是我们需要的配置,我们只要配置{updateOn: 'blur'}应该就可以达到我们的需求了。

但是我们项目中使用的是FormBulider啊,我们怎么应用在FormBuilder里面呢?

看看文档上关于FormBuilder的介绍,我们只需要关注FormGroup.group

1
group(controlsConfig: { [key: string]: any; }, options: AbstractControlOptions | { [key: string]: any; } = null): FormGroup

噢,nice,group的第二个参数里面也包含着AbstractControlOptions的类型。那我们尝试下载项目中设置:

1
2
3
4
5
 this.validateForm = this.fb.group({
code: [null, [Validators.required, Validators.minLength(2), Validators.maxLength(6)]],
}, {
updateOn: 'blur',
});

然后运行项目,在页面中尝试输入,发现在输入的时候同时进行验证,也就是说,并没有起作用。

why?

去看看项目中的文件,暗中command同时鼠标点击this.fb.group中的group,跳转到项目中引用的angular的FormBuilder的定义,我们发现其中定义group;

1
2
3
4
5
6
7
8
9
10
* @param extra An object of configuration options for the `FormGroup`.
* * `validator`: A synchronous validator function, or an array of validator functions
* * `asyncValidator`: A single async validator or array of async validator functions
*
*/
group(controlsConfig: {
[key: string]: any;
}, extra?: {
[key: string]: any;
} | null): FormGroup;

也就是第二个参数只是一个配置项,里面只有同步验证器和异步验证器,并没有updateOn参数的配置。文档和项目中并不全配套,文档只是一个解释,具体还得看项目中的定义啊。

那我们将其改写为FormGroup的形式:

1
2
3
4
5
6
7
 this.formGroup = new FormGroup({
code: new FormControl(null, {
validators: [Validators.required, Validators.minLength(2), Validators.maxLength(4)],
}),
}, {
updateOn: 'blur',
});

然后在页面中输入测试,发现只有在遗失焦点之后才会进行验证,实现~


再回头看看updateOn配置,一直在用响应式表单也没了解过这个参数。确实有时候在用户一直输入的时候去更新去验证不仅仅是有一点不好的用户体验,更会消耗资源,而通过updateOn这个参数可以改变验证发生的时间点,有三个值:

  • change 在输入改变的时候就进行验证
  • blur 在遗失焦点的时候进行验证
  • submit 在提交的时候进行验证
码字辛苦,打赏个咖啡☕️可好?💘