Angular中,form表单的验证功能是非常重要且实用的,下面来具体看一下如何正确的使用Angular表单验证:
-
angular 内置验证器
首先,Angular中提供了一系列的内置验证器,如required,min,minLength等。
下面构建一个简单的表单与loginForm绑定,其中包含两个input,分别为name和password:
<form [formGroup]='loginForm'> <div> name: <input type="text" formControlName='name' forbiddenName='any'> <span *ngIf='name.invalid && (name.dirty || name.touched)'> <span *ngIf='name.errors.required'>name不能为空</span> <span *ngIf='name.errors.minlength'>name不能少于两个字符</span> </span> </div> <div> password: <input type="password" formControlName='password'> <span *ngIf='password.invalid && (password.dirty || password.touched)'> <span *ngIf='password.errors.required'>password不能为空</span> </span> </div> <button type="submit">Submit</button> </form>在组件初始化时,对loginForm进行实例化,并且为name和password都绑定了表单控件FormControl;在FormControl实例化过程中,传入了两个参数,第一个参数为控件的初始化值;第二个参数则是应用到控件上的同步验证器数组;FormControl可以接受第三个参数进行异步验证,此时暂且忽略。
为name控件设置了两个验证器:Validators.required和Validators.minLength(2),分别验证name字段必填项且长度不小于2;password控件也为必填项。
同时,为name和password属性添加了getter方法,这样能够简化在html模板中的代码,可以直接使用
name.errors.required或取错误信息,相当于使用loginForm.get('name').errors.required。 另外,还添加了
name.invalid && (name.dirty || name.touched)的验证,以在保证用户未输入前不显示错误信息。export class FormDemoComponent implements OnInit { loginForm: FormGroup; constructor() { } ngOnInit(): void { this.loginForm = new FormGroup({ name: new FormControl('default name', [ Validators.required, Validators.minLength(2) ]), password: new FormControl('', [ Validators.required ]) }); } get name() { return this.loginForm.get('name'); } get password() { return this.loginForm.get('password'); } } -
自定义验证器
除了Angular提供的内置验证器外,也可以给控件添加自定义的验证器,如自定义一个验证器,验证name中不能是admin。
定义如下的验证器函数customNameValidation(),它实际返回一个配置好的验证器函数。该函数接受一个AbstractControl对象,控制器值合法时返回null,不合法则返回验证错误的对象,invalidName作为其中的属性名。
customNameValidation(): ValidatorFn { return (control: AbstractControl): { [key: string]: any } | null => { if (control.value === 'admin') { return { 'invalidName': { value: control.value } }; } else { return null; } }; }将上述自定义的验证器,传入name控件的同步验证器数组中:
this.loginForm = new FormGroup({ name: new FormControl('default name', [ Validators.required, Validators.minLength(2), this.customNameValidation() // 自定义验证器 ]), password: new FormControl('', [ Validators.required ]) });与内置验证器一致,在对应的HTML模板中,可以通过
name.errors.invalidName获取错误,如下显示错误信息:<span *ngIf='name.errors.invalidName'>name不能为admin</span> -
自定义验证器指令
除了在FormControl中添加自定义验证器之外,也可以通过指令(directive)的形式,通过html模板添加验证器。
新建一个ForbiddenNameDirective,使它符合Angular form模块中提供的Validator接口,注意要将此指令注册到NG_VALIDATORS提供商中,且使用useExisting进行实例化;在validate方法中,调用自定义的验证器函数forbiddenNameValidation(),该方法接受一个string类型的参数,作为name字段不可用的特殊字符串。
import { Directive, Input } from '@angular/core'; import { ValidatorFn, AbstractControl, Validator, NG_VALIDATORS } from '@angular/forms'; export function forbiddenNameValidation(regName: string): ValidatorFn { return (control: AbstractControl): { [key: string]: any } => { if (control.value === RegName) { return { 'forbiddenName': { value: control.value } }; } }; } @Directive({ selector: '[forbiddenName]', providers: [{provide: NG_VALIDATORS, useExisting: ForbiddenNameDirective, multi: true}] }) export class ForbiddenNameDirective implements Validator { @Input() forbiddenName: string; constructor() { } validate(control: AbstractControl): { [key: string]: any } | null { return this.forbiddenName ? forbiddenNameValidation(this.forbiddenName)(control) : null; } }与前一个例子稍有不同,因为并没有将不合法的name设为固定值,在模板中使用该指令可以传入该值,此处以‘any’为例
forbiddenName='any':name: <input type="text" formControlName='name' forbiddenName='any'> <span *ngIf='name.invalid && (name.dirty || name.touched)'> <span *ngIf='name.errors.forbiddenName'>name不能为any</span> </span> -
跨字段交叉验证
除了对单个控件进行验证外,angular也支持跨字段进行交叉验证,可以在FormGroup进行自定义验证;如验证name和password值不能相同。
首先,自定义一个验证器,返回一个配置好的验证器函数;在实例化FormGroup,把新建的验证器传给第二个参数:
customNameValidation(): ValidatorFn { return (control: AbstractControl): { [key: string]: any } | null => { if (control.value === 'admin') { return { 'invalidName': { value: control.value } }; } else { return null; } }; } buildFormGroup() { this.loginForm = new FormGroup({ name: new FormControl(), password: new FormControl() }, {validators: this.customGroupValidator}); }在html模板中,使用
loginForm.errors?.namePasswordSame获取错误信息:<span *ngIf='loginForm.errors?.namePasswordSame'> name and password can not be same!</span>