表单验证
通常,我们都需要对用户的表单输入做验证,以保证数据的整体质量。
Angular
也有两种验证表单的形式:
- 使用属性验证,用于模板驱动表单;
- 使用验证器函数进行验证,用于响应式表单。
验证器(Validator)函数
验证器函数可以是同步函数,也可以是异步函数。
- 同步验证器:接受控件实例,然后返回验证错误信息或
null
。在实例化一个FormControl
时把它作为构造函数的第二个参数传进去; - 异步验证器 :接受实例并返回一个
Promise
或Observable
,稍后会发出一组验证错误或null
。也是在实例化FormControl
时,作为第三个参数传入。
内置验证器函数
Angular
内置了一些基础功能的验证器,在日常开发中可以直接使用:
我们来简单使用一下内置的验证器:
// reactive-forms.component.ts
import {
Validators} from '@angular/forms';
...
profileForm = this.fb.group({
firstName: ['', Validators.required], // 必填
lastName: ['',
[Validators.required, Validators.minLength(4)]
], // 必填并且最小长度为4
...
});
// 因为我们可能多次获取表单中元素,所以先获取
get firstName() {
return this.profileForm.get('firstName'); }
get lastName() {
return this.profileForm.get('lastName'); }
<!-- reactive-forms.component.html -->
<form [formGroup]="profileForm" (ngSubmit)="onSubmit()">
<div class="form-group">
<label>
First Name: <input type="text" formControlName="firstName" class="form-control form-control-sm">
</label>
<div class="alert alert-danger">
valid: {
{firstName.valid | json}} <br>
errors: {
{firstName.errors | json}}
</div>
</div>
<div class="form-group">
<label>
Last Name: <input type="text" formControlName="lastName" class="form-control form-control-sm">
</label>
<div class="alert alert-danger">
valid: {
{lastName.valid | json}} <br>
errors: {
{lastName.errors | json}}
</div>
</div>
</form>
效果是这样的:
可以看出:必填验证一开始都没有通过,验证顺序是跟添加验证器的顺序一致。
上一节最后我们不是介绍过 Angular
跟踪控件状态吗,那就可以根据状态去控制错误提示。
在日常开发中,当我们表单是必填项,初始化页面时,我们是不应该提示错误,并且,如果用户聚焦后并没有输入任何值的时候,也是不应该提示错误的。
<!-- reactive-forms.component.html -->
<form [formGroup]="profileForm" (ngSubmit)="onSubmit()">
<div class="form-group">
<label>
First Name: <input type="text" formControlName="firstName" class="form-control form-control-sm">
</label>
<div *ngIf="firstName.dirty && firstName.errors" class="alert alert-danger">
<span>请填写first name</span>
</div>
</div>
<div class="form-group">
<label>
Last Name: <input type="text" formControlName="lastName" class="form-control form-control-sm">
</label>
<div *ngIf="lastName.dirty && lastName.errors as errors" class="alert alert-danger">
<span *ngIf="errors.required">请填写last name</span>
<span *ngIf="errors.minlength">last name应该至少4个字符</span>
</div>
</div>
</form>
上面的dirty
是 AbstractControl
类的属性,用于判定控件是否修改过控件的值。
AbstractControl
类还有其他监控用户操作控件的属性:
pristine: boolean
如果用户尚未修改UI
中的值,则该控件是pristine
(原始状态)的。touched: boolean
一旦用户在控件上触发了blur
事件,则会将其标记为touched
。untouched: boolean
如果用户尚未在控件上触发过blur
事件,则该控件为untouched
。
定义自定义验证器
内置的验证器并不是总能适用于我们的需求,因此需要创建自定义验证器。
创建自定义验证器,我们需要遵从 Angular
中的创建规则:
-
验证器函数的返回值必须是
ValidatorFn
类型;ValidatorFn
实际上是一个接口,里面只有一个方法,将一个表单控件传入,返回验证错误信息(ValidationErrors
)或者null
ValidationErrors
是一个key: value
的对象
搞清楚了规则,我们的验证器函数至少应该是这样的:
function validatorName(): ValidatorFn {
return (control: AbstractControl): ValidationErrors | null => {
const isValid: boolean;
return isValid ? null : {
validateName: 'error info'};
};
}
按照上面的样子,我们来写一个通过正则验证字符串中不能包含特定字符的验证器函数(新建validators.ts):
// validators.ts
import {
AbstractControl, Valid