Angular 的内置验证器由 Validators 模块提供,如果想要为 FormControl 对象添加验证器,直接将验证器作为 FormControl 的第二个参数即可。
下面例子中列举了比较常用的内置验证器及其使用形式:
例子:
form.component.html
<form [formGroup]="myGroup"> <ul> <li> 姓名:<input type="text" formControlName="name"> </li> <li> 性别:<input type="text" formControlName="sex"> </li> <li> 年龄:<input type="number" formControlName="age"> </li> <li> 血型:<input type="text" formControlName="type"> </li> </ul> </form>
form.component.ts
import { Component, OnInit } from '@angular/core'; // 导入校验接口 Validators import { FormGroup, FormControl, FormBuilder, Validators } from '@angular/forms'; @Component({ selector: 'app-form', templateUrl: './form.component.html', styleUrls: ['./form.component.scss'] }) export class FormComponent implements OnInit { myGroup!: FormGroup; constructor( private fb: FormBuilder, ) { } ngOnInit() { this.myGroup = this.fb.group({ // 添加必填校验:required name:['', Validators.required], // 添加单个校验规则的其他方法: // new FormControl('', Validators.required); // this.fb.control('', Validators.required); // 添加字符长度校验:minLength()、maxLength() sex:['', [Validators.required, Validators.maxLength(1)]], // 添加多个校验规则的其他方法: // new FormControl('', [Validators.required, Validators.maxLength(1)]); // this.fb.control('', [Validators.required, Validators.maxLength(1)]); // 添加数值大小校验:min()、max() age: ['', [Validators.required, Validators.min(6)]], // 添加正则表达式:pattern() type:['', [Validators.pattern('[a-zA-Z ]*'), Validators.maxLength(2)]] }); } }
我们也可以创建自己的验证器。
项目结构:
例子:
form-validators.service.ts
import { Injectable } from '@angular/core'; import { ValidatorFn, FormControl, AbstractControl } from '@angular/forms'; @Injectable() export class FormValidatorsService { constructor() { } // c: FormControl 或者 c: AbstractControl 都指向需要验证的内容 // AbstractControl 是 FormControl 的基类,因此它们共享 value 属性,使用哪个都可以 // 如果验证失败,返回 {[key: string]: boolean} 对象,key 为错误代码,自定义即可,boolean 为 true // 如果验证成功,返回 null phoneNumberValidator(c: FormControl): {[key: string]: boolean} | null { // 验证手机号是否以数字'1'开头 if (!c.value.match(/^1/)) { return { 'phoneNumber': true }; } return null; } // 验证器函数传参的写法 areaNumberValidator(param: string): ValidatorFn { return (c: AbstractControl): {[key: string]: boolean} | null => { // 验证座机区号是否为 param if(!c.value.startsWith(param)) { return { 'areaNumber': true}; } return null; } } }
form.component.html
<form [formGroup]="myGroup"> <p> 手机:<input type="tel" formControlName="phoneNumber"> </p> <p> 座机:<input type="tel" formControlName="areaNumber"> </p> </form>
form.component.ts
import { Component, OnInit } from '@angular/core'; import { FormGroup, FormControl, FormBuilder, Validators } from '@angular/forms'; // 导入自定义验证器 FormValidatorsService import { FormValidatorsService } from './service/form-validators.service' @Component({ selector: 'app-form', templateUrl: './form.component.html', styleUrls: ['./form.component.scss'], // 将 FormValidatorsService 注入组件 providers: [ FormValidatorsService ], }) export class FormComponent implements OnInit { myGroup!: FormGroup; constructor( private fb: FormBuilder, // 初始化 FormValidatorsService private formValidators: FormValidatorsService ) { } ngOnInit() { this.myGroup = this.fb.group({ // 添加 phoneNumberValidator 验证器 phoneNumber:['', [Validators.required, this.formValidators.phoneNumberValidator]], // 添加 areaNumberValidator 验证器,该验证器可以传参 areaNumber:['', [Validators.required, this.formValidators.areaNumberValidator('0411')]], }); } }
FormControl 与 FormGroup 的关系
FormControl 与 FormGroup 都继承自基类
AbstractControl
,因此,FormControl 与
FormGroup 共享着AbstractControl
的属性和方法,比如 value、valid、valueChanges() 等等。
FormControl 封装了单个输入字段的值和状态,比如字段是否有效,是否被修改过或者是否有错误等等。
而 FormGroup 的意义在于管理多个 FormControl,为一组 FormControl 提供总的接口,比如我们要验证多个 FormControl 是否有效(valid 属性),就需要遍历每一个 FormControl,比较繁琐,这种情况下,使用 FormGroup 就可以轻松地解决问题。
检查整个表单的有效性
结合我上面的介绍,我们通过 FormGroup 的属性 valid 就可以检查整个表单的有效性,只有当所有的 FormControl 都有效时,这个 FormGroup 才会有效。
例子:
form.component.html
<form [formGroup]="myGroup"> <p> 手机:<input type="tel" formControlName="phoneNumber"> </p> <p> 座机:<input type="tel" formControlName="areaNumber"> </p> <p style="color: red;">{{ errMsg }}</p> <button (click)="save()">提交</button> </form>
form.component.ts
import { Component, OnInit } from '@angular/core'; import { FormGroup, FormControl, FormBuilder, Validators } from '@angular/forms'; @Component({ selector: 'app-form', templateUrl: './form.component.html', styleUrls: ['./form.component.scss'] }) export class FormComponent implements OnInit { myGroup!: FormGroup; errMsg!: string; constructor( private fb: FormBuilder ) {} ngOnInit() { this.myGroup = this.fb.group({ phoneNumber:['', Validators.required], areaNumber:['', Validators.required], }); } // 验证整个表单的有效性并显示错误信息 save() :boolean{ if(!this.myGroup.valid){ this.errMsg = '验证未通过!'; return false; } console.log(this.myGroup.value); this.errMsg = ''; return true; } }
检查单个字段的有效性
很多时候,我们需要知道哪个字段无效,导致了验证的失败,所以,检查单个字段的有效性并显示错误消息是更加实际的需求。
为单个 FormControl 进行验证,我们必须为每个字段定义一个变量,并为变量添加 getter 方法。
例子:
form.component.ts
import { Component, OnInit } from '@angular/core'; import { FormGroup, FormControl, FormBuilder, Validators } from '@angular/forms'; @Component({ selector: 'app-form', templateUrl: './form.component.html', styleUrls: ['./form.component.scss'] }) export class FormComponent implements OnInit { myGroup!: FormGroup; errMsg!: string; // 声明变量 phoneNumber、areaNumber // 这样,在组件和模板中,就可以到处引用变量 get phoneNumber(){ // 使用 FormGroup 的 get 方法或 controls 获取单个字段 return this.myGroup.get('phoneNumber'); // return this.myGroup.controls['phoneNumber']; } get areaNumber(){ return this.myGroup.get('areaNumber'); // return this.myGroup.controls['areaNumber']; } constructor( private fb: FormBuilder ) {} ngOnInit() { this.myGroup = this.fb.group({ phoneNumber:['', Validators.required], areaNumber:['', Validators.required], }); } save() :boolean{ if(!this.myGroup.valid){ console.log('保存失败'); return false; } console.log(this.myGroup.value); return true; } }
form.component.html
<form [formGroup]="myGroup"> <p> 手机:<input type="tel" formControlName="phoneNumber"> <!-- 在模板中引用变量 --> <!-- phoneNumber.valid:验证 phoneNumber 是否有效 --> <!-- phoneNumber.touched:验证 phoneNumber 是否被修改 --> <i style="color: red;" *ngIf="!phoneNumber?.valid && phoneNumber?.touched">手机验证未通过!</i> </p> <p> 座机:<input type="tel" formControlName="areaNumber"> <i style="color: red;" *ngIf="!areaNumber?.valid && areaNumber?.touched">座机验证未通过!</i> </p> <button (click)="save()">提交</button> </form>
特定验证
一个字段可能添加了很多验证器,对于失败的原因,我们更希望根据不同的原因提示不同的消息。
我们可以使用 hasError() 检查哪些验证失败。
例子:
form.component.ts
import { Component, OnInit } from '@angular/core'; import { FormGroup, FormControl, FormBuilder, Validators } from '@angular/forms'; @Component({ selector: 'app-form', templateUrl: './form.component.html', styleUrls: ['./form.component.scss'] }) export class FormComponent implements OnInit { myGroup!: FormGroup; errMsg!: string; get phoneNumber(){ return this.myGroup.get('phoneNumber'); } constructor( private fb: FormBuilder ) {} ngOnInit() { this.myGroup = this.fb.group({ phoneNumber:['', [Validators.required, Validators.pattern('^[0-9]*$')] ] }); } save() :boolean{ if(!this.myGroup.valid){ console.log('保存失败'); return false; } console.log(this.myGroup.value); return true; } }
form.component.html
<form [formGroup]="myGroup"> <p> 手机:<input type="tel" formControlName="phoneNumber"> <span style="color: red;" *ngIf="!phoneNumber?.valid && phoneNumber?.touched"> <i *ngIf="phoneNumber?.hasError('required')">必填!</i> <i *ngIf="phoneNumber?.hasError('pattern')">必须是数字!</i> </span> </p> <button (click)="save()">提交</button> </form>
end