強(qiáng)大的 Angular 表單驗(yàn)證功能詳細(xì)介紹
Angular 支持非常強(qiáng)大的內(nèi)置表單驗(yàn)證,maxlength、minlength、required 以及 pattern。使用 Angular 的內(nèi)置表單校驗(yàn)?zāi)軌蛲瓿山^大多數(shù)的業(yè)務(wù)場(chǎng)景的校驗(yàn)需求,但有時(shí)我們還需要實(shí)現(xiàn)更為復(fù)雜的表單校驗(yàn)功能,這時(shí)可以使用 Angular 提供的表單自定義校驗(yàn)(Custom Validator)。下面,我們就來(lái)了解一下如何使用 Angular 的自定義表單校驗(yàn)
效果圖:

1、首先,來(lái)創(chuàng)建我們的注冊(cè)組件(register),并在模版中顯示一個(gè)簡(jiǎn)單的表單
<h3 class="text-center">注冊(cè)</h3> <form> <div class="form-group"> <label for="username">用戶名:</label> <input type="text" id="username" class="form-control" > </div> </form>
為了使表單看上去能夠漂亮一些,在 index.html 中引入 bootstrap 樣式文件:
<link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
2、接下來(lái)確定我們的驗(yàn)證需求:
我們希望用戶名只能包含數(shù)字、字母和下劃線,且不能以下劃線開(kāi)頭
首先為 form 標(biāo)簽添加 formGroup 指令:
<form [formGroup]="registerForm" >
并且為 input 標(biāo)簽添加 formControlName 指令:
<input formControlName="username" type="text" id="username" class="form-control" >
3、在代碼中定義驗(yàn)證規(guī)則:
從內(nèi)置表單模塊中導(dǎo)入以下類:
import { FormBuilder, FormGroup, Validators } from '@angular/forms';其中:
1. formBuilder 用來(lái)構(gòu)建表單數(shù)據(jù)
2. formGroup 表示表單類型
3. Validators 包含了表單內(nèi)置的驗(yàn)證規(guī)則,如: Validators.required
定義表單屬性
registerForm: FormGroup;
定義表單驗(yàn)證不通過(guò)時(shí)每一項(xiàng)顯示的錯(cuò)誤消息(目前我們只有 username )
formErrors = {
username: ''
};為每一項(xiàng)驗(yàn)證規(guī)則定義驗(yàn)證失敗時(shí)的說(shuō)明文字(表單控件可能有多條驗(yàn)證規(guī)則,由不通過(guò)的驗(yàn)證說(shuō)明構(gòu)成一條錯(cuò)誤消息)
validationMessage = {
'username': {
'minlength': '用戶名長(zhǎng)度最少為3個(gè)字符',
'maxlength': '用戶名長(zhǎng)度最多為10個(gè)字符',
'required': '請(qǐng)?zhí)顚?xiě)用戶名'
}
};
在構(gòu)造函數(shù)中添加 fb 屬性用來(lái)構(gòu)建表單
constructor(private fb: FormBuilder) { }添加構(gòu)建表單的方法
buildForm(): void {
// 通過(guò) formBuilder構(gòu)建表單
this.registerForm = this.fb.group({
/* 為 username 添加3項(xiàng)驗(yàn)證規(guī)則:
* 1.必填, 2.最大長(zhǎng)度為10, 3.最小長(zhǎng)度為3
* 其中第一個(gè)空字符串參數(shù)為表單的默認(rèn)值
*/
'username': [ '', [
Validators.required,
Validators.maxLength(10),
Validators.minLength(3)
]]
});接下來(lái)我們添加一個(gè)方法用來(lái)更新錯(cuò)誤信息
onValueChanged(data?: any) {
// 如果表單不存在則返回
if (!this.registerForm) return;
// 獲取當(dāng)前的表單
const form = this.registerForm;
// 遍歷錯(cuò)誤消息對(duì)象
for (const field in this.formErrors) {
// 清空當(dāng)前的錯(cuò)誤消息
this.formErrors[field] = '';
// 獲取當(dāng)前表單的控件
const control = form.get(field);
// 當(dāng)前表單存在此空間控件 && 此控件沒(méi)有被修改 && 此控件驗(yàn)證不通過(guò)
if (control && control.dirty && !control.valid) {
// 獲取驗(yàn)證不通過(guò)的控件名,為了獲取更詳細(xì)的不通過(guò)信息
const messages = this.validationMessage[field];
// 遍歷當(dāng)前控件的錯(cuò)誤對(duì)象,獲取到驗(yàn)證不通過(guò)的屬性
for (const key in control.errors) {
// 把所有驗(yàn)證不通過(guò)項(xiàng)的說(shuō)明文字拼接成錯(cuò)誤消息
this.formErrors[field] += messages[key] + '\n';
}
}
}
}
下面只需要在表單構(gòu)建結(jié)束后初始化錯(cuò)誤消息,并且在每次表單數(shù)據(jù)更改時(shí)更新錯(cuò)誤消息就可以了
在 buildForm 方法中添加如下代碼
// 每次表單數(shù)據(jù)發(fā)生變化的時(shí)候更新錯(cuò)誤信息 this.registerForm.valueChanges .subscribe(data => this.onValueChanged(data)); // 初始化錯(cuò)誤信息 this.onValueChanged();
此時(shí),我們已經(jīng)很好的控制了錯(cuò)誤信息,下面只需要在表單模版中添加錯(cuò)誤信息的顯示就可以了
在 input 標(biāo)簽下方添加如下代碼:
<div *ngIf="formErrors.username"
class="showerr alert alert-danger" >{{ formErrors.username }}</div>添加如下代碼到表單模版的 css 中:
form {
width: 90%;
max-width: 45em;
margin: auto;
}
.showerr {
white-space: pre-wrap;
}
現(xiàn)在我們就可以嘗試運(yùn)行了,在代碼不報(bào)錯(cuò)的情況下已經(jīng)能夠看到非常好的效果了
如果代碼報(bào)錯(cuò)或沒(méi)有出現(xiàn)想象中的效果則可以參照本文結(jié)尾的完整代碼進(jìn)行修改
4、雖然我們已經(jīng)搭建了整個(gè)布局,但是還沒(méi)有實(shí)現(xiàn)我們的最終目的:實(shí)現(xiàn)自定義的表單驗(yàn)證
接下來(lái)我們創(chuàng)建一個(gè)正則驗(yàn)證器,新建文件 validate-register.ts :
import { ValidatorFn, AbstractControl } from '@angular/forms';
export function validateRex(type: string, validateRex: RegExp): ValidatorFn {
return (control: AbstractControl): {[key: string]: any} => {
// 獲取當(dāng)前控件的內(nèi)容
const str = control.value;
// 設(shè)置我們自定義的驗(yàn)證類型
const res = {};
res[type] = {str}
// 如果驗(yàn)證通過(guò)則返回 null 否則返回一個(gè)對(duì)象(包含我們自定義的屬性)
return validateRex.test(str) ? null : res;
}
}
下面我們?cè)诖a中導(dǎo)入此函數(shù):
import { validateRex } from './validate-register';修改 validationMessage 屬性為:
// 為每一項(xiàng)表單驗(yàn)證添加說(shuō)明文字
validationMessage = {
'username': {
'minlength': '用戶名長(zhǎng)度最少為3個(gè)字符',
'maxlength': '用戶名長(zhǎng)度最多為10個(gè)字符',
'required': '請(qǐng)?zhí)顚?xiě)用戶名',
'notdown': '用戶名不能以下劃線開(kāi)頭',
'only': '用戶名只能包含數(shù)字、字母、下劃線'
}
};修改 buildForm 方法:
// 通過(guò) formBuilder構(gòu)建表單
this.registerForm = this.fb.group({
/* 為 username 添加 5 項(xiàng)驗(yàn)證規(guī)則:
* 1.必填, 2.最大長(zhǎng)度為10, 3.最小長(zhǎng)度為3, 4.不能以下劃線開(kāi)頭, 5.只能包含數(shù)字、字母、下劃線
* 其中第一個(gè)空字符串參數(shù)為表單的默認(rèn)值
*/
'username': [ '', [
Validators.required,
Validators.maxLength(10),
Validators.minLength(3),
validateRex('notdown', /^(?!_)/),
validateRex('only', /^[1-9a-zA-Z_]+$/)
]]
});
OK ! 大功告成了,趕緊運(yùn)行代碼嘗試一下吧,我們可以隨時(shí)添加各種驗(yàn)證規(guī)則,只需要修改 validationMessage 屬性和 buildForm 方法即可!
如果添加多個(gè)表單控件的話還需要修改 formErrors,例如添加 password 控件則修改 formErrors 為
formErrors = {
username: '',
password: ''
};大家可自行嘗試一下!
完整代碼:
register.component.html
<h3 class="text-center">注冊(cè)</h3>
<form [formGroup]="registerForm" >
<div class="form-group">
<label for="username">用戶名:</label>
<input formControlName="username"
type="text" id="username" #username
class="form-control" >
<div *ngIf="formErrors.username" class="showerr alert alert-danger" >{{ formErrors.username }}</div>
</div>
</form>
register.component.css:
form {
width: 90%;
max-width: 45em;
margin: auto;
}
.showerr {
white-space: pre-wrap;
}
register.component.ts:
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { validateRex } from './validate-register';
@Component({
selector: 'app-register',
templateUrl: './register.component.html',
styleUrls: ['./register.component.css']
})
export class RegisterComponent implements OnInit {
// 定義表單
registerForm: FormGroup;
// 表單驗(yàn)證不通過(guò)時(shí)顯示的錯(cuò)誤消息
formErrors = {
username: ''
};
// 為每一項(xiàng)表單驗(yàn)證添加說(shuō)明文字
validationMessage = {
'username': {
'minlength': '用戶名長(zhǎng)度最少為3個(gè)字符',
'maxlength': '用戶名長(zhǎng)度最多為10個(gè)字符',
'required': '請(qǐng)?zhí)顚?xiě)用戶名',
'notdown': '用戶名不能以下劃線開(kāi)頭',
'only': '用戶名只能包含數(shù)字、字母、下劃線'
}
};
// 添加 fb 屬性,用來(lái)創(chuàng)建表單
constructor(private fb: FormBuilder) { }
ngOnInit() {
// 初始化時(shí)構(gòu)建表單
this.buildForm();
}
// 構(gòu)建表單方法
buildForm(): void {
// 通過(guò) formBuilder構(gòu)建表單
this.registerForm = this.fb.group({
/* 為 username 添加3項(xiàng)驗(yàn)證規(guī)則:
* 1.必填, 2.最大長(zhǎng)度為10, 3.最小長(zhǎng)度為3, 4.不能以下劃線開(kāi)頭, 5.只能包含數(shù)字、字母、下劃線
* 其中第一個(gè)空字符串參數(shù)為表單的默認(rèn)值
*/
'username': [ '', [
Validators.required,
Validators.maxLength(10),
Validators.minLength(3),
validateRex('notdown', /^(?!_)/),
validateRex('only', /^[1-9a-zA-Z_]+$/)
]]
});
// 每次表單數(shù)據(jù)發(fā)生變化的時(shí)候更新錯(cuò)誤信息
this.registerForm.valueChanges
.subscribe(data => this.onValueChanged(data));
// 初始化錯(cuò)誤信息
this.onValueChanged();
}
// 每次數(shù)據(jù)發(fā)生改變時(shí)觸發(fā)此方法
onValueChanged(data?: any) {
// 如果表單不存在則返回
if (!this.registerForm) return;
// 獲取當(dāng)前的表單
const form = this.registerForm;
// 遍歷錯(cuò)誤消息對(duì)象
for (const field in this.formErrors) {
// 清空當(dāng)前的錯(cuò)誤消息
this.formErrors[field] = '';
// 獲取當(dāng)前表單的控件
const control = form.get(field);
// 當(dāng)前表單存在此空間控件 && 此控件沒(méi)有被修改 && 此控件驗(yàn)證不通過(guò)
if (control && control.dirty && !control.valid) {
// 獲取驗(yàn)證不通過(guò)的控件名,為了獲取更詳細(xì)的不通過(guò)信息
const messages = this.validationMessage[field];
// 遍歷當(dāng)前控件的錯(cuò)誤對(duì)象,獲取到驗(yàn)證不通過(guò)的屬性
for (const key in control.errors) {
// 把所有驗(yàn)證不通過(guò)項(xiàng)的說(shuō)明文字拼接成錯(cuò)誤消息
this.formErrors[field] += messages[key] + '\n';
}
}
}
}
}
validate-register.ts:
import { ValidatorFn, AbstractControl } from '@angular/forms';
export function validateRex(type: string, validateRex: RegExp): ValidatorFn {
return (control: AbstractControl): {[key: string]: any} => {
// 獲取當(dāng)前控件的內(nèi)容
const str = control.value;
// 設(shè)置我們自定義的嚴(yán)重類型
const res = {};
res[type] = {str}
// 如果驗(yàn)證通過(guò)則返回 null 否則返回一個(gè)對(duì)象(包含我們自定義的屬性)
return validateRex.test(str) ? null : res;
}
}
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Angularjs實(shí)現(xiàn)mvvm式的選項(xiàng)卡示例代碼
每位Web開(kāi)發(fā)者應(yīng)該都知道,選項(xiàng)卡是現(xiàn)代web網(wǎng)頁(yè)中最常用的效果之一,所以本文重點(diǎn)是用angularjs這個(gè)非?;餸vvm框架,實(shí)現(xiàn)選項(xiàng)卡效果。有需要的朋友們可以參考借鑒,下面來(lái)一起看看吧。2016-09-09
詳解Angular路由 ng-route和ui-router的區(qū)別
這篇文章主要介紹了詳解Angular路由 ng-route和ui-router的區(qū)別,分別介紹了兩種路由的用法和區(qū)別,有興趣的可以了解一下2017-05-05
angular中的http攔截器Interceptors的實(shí)現(xiàn)
本篇文章主要介紹了angular中的http攔截器Interceptors的實(shí)現(xiàn)的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。2017-02-02
AngularJS基礎(chǔ) ng-switch 指令簡(jiǎn)單示例
本文主要講解AngularJS ng-switch 指令,這里對(duì)ng-switch 指令的基礎(chǔ)資料做了詳細(xì)整理,并附代碼示例,有興趣的小伙伴可以參考下2016-08-08
探索angularjs+requirejs全面實(shí)現(xiàn)按需加載的套路
這篇文章主要探索了angularjs+requirejs全面實(shí)現(xiàn)按需加載的套路,圍繞angularjs提供的各種機(jī)制進(jìn)行研究,感興趣的小伙伴們可以參考一下2016-02-02

