在使用 AngularJS 進行開發的時候,表單填寫是一個很常見的需求,而表單驗證又是比較讓人頭疼的部分,本文對此作一個總結。javascript
在 Angular 的視圖中使用的 form 已經不是 HTML 中的普通 form 了,而是一個被 Angular 封裝過的指令。它能夠完成普通 form 沒法實現的功能,好比 form 嵌套,並且自帶強大的驗證功能。css
Angular 在對錶單進行校驗的時候會使用 ngModelController
上的屬性,若是不設置 ng-model
,則 Angular 沒法知道 form.$invalid
這個值是否爲真。後面在自定義驗證有對它的介紹。html
本文在對錶單的驗證時使用了 ng-messages
,在文章最後也有對它的介紹。java
在 form 層面,可使用 ng-disabled
來控制提交按鈕的狀態,在 form 表單項所有驗證經過前不可點擊,下面介紹一下通用的表單項驗證選項。angularjs
AngularJS 的 input 標籤 自帶的驗證選項有如下這些。github
<input ng-model="" [name=""] [required=""] [ng-required=""] [ng-minlength=""] [ng-maxlength=""] [ng-pattern=""] [ng-change=""]> ... </input>
a. 必填api
<input type="text" name="myName" ng-model="username" required />
使用 ng-required
能夠根據後面表達式的值設置是否 required
。promise
在不知足 required
時 form.myName.$error
爲 {required: true}
。app
b. 長度
<input type="text" name="myName" ng-model="username" ng-minlength="2" ng-maxlength="10" />
在不知足 ng-minlength
/ng-maxlength
時 form.myName.$error
爲 {minlength: true, maxlength: true}
。
直接使用 minlength
/maxlength
也有相同效果,並且 maxlength
能夠設置最多輸入 x 個字符,超過以後沒法再輸入。
c. 模式匹配
<input type="text" name="myDesc" ng-model="desc" ng-pattern="/^[a-zA-Z]{1,20}$/" />
在不知足 ng-pattern
時 form.myName.$error
爲 {pattern: true}
。
d. 其餘
AngularJS 對特定格式也進行了校驗。好比將 type
設置爲 url
,email
等,在沒有特殊驗證要求的狀況下,能夠直接使用這些自帶的校驗,或者經過自定義指令修改 Angular 內建驗證器。不一樣 type 有不一樣的驗證選項,具體參考 AngularJS API 文檔。
Angular 會根據表單狀態自動給表單和表單項添加如下幾組樣式:
ng-valid
驗證經過,與之相對的是 ng-invalid
ng-valid-[key]
經過自定義驗證器添加的驗證經過的值,與之相對的是 ng-invalid-[key]
ng-pristine
未交互狀態,與之相對的是 ng-dirty
ng-touched
未訪問狀態,與之相對的是 ng-untouched
ng-pending
知足 $asyncValidators
的狀況
這些在 ngModelController 的屬性中都有對應值。
根據這些 class,能夠爲不一樣狀態設置不一樣的樣式,好比這樣:
input.ng-valid.ng-dirty { border-color: #78FA89; } input.ng-invalid.ng-dirty { border-color: #FA787E; }
在 AngularJS 指令入門 一文中,提到過經過 require 屬性和 controller 參數,能夠實現指令之間的交互。那麼,在自定義指令中使用 require: 'ngModel'
就可使用 ngModel
指令的 controller 屬性的實例了。
ngModel 提供了數據綁定、驗證、CSS更新、數據格式化和編譯等操做。下面簡單介紹一下 ngModelController 經常使用的屬性和方法。
$viewValue
視圖裏的值
$modelValue
數據模型裏值
在 input
事件觸發的時候,$viewValue
會同步到 $modelValue
。默認狀況下,這個是一旦 input
中的內容有改變就觸發。AngularJS 1.3 引入了 ng-model-options
,可讓這個同步延遲到 blur 或者延遲必定的時間以後。
<input type="text" name="username" ng-model="username" ng-model-options="{updateOn:'blur'}"> <input type="text" name="username" ng-model="username" ng-model-options="{ debounce: 500 }">
在 $viewValue
的值同步到 $modelValue
時,會通過 $parsers
、$validators
和 $asyncValidators
三個核心管道(後兩個是 AngularJS 1.3 之後新加的)進行處理,經過後才更新到 $modelValue
上(若是驗證器管道沒經過,不會更新)。
$parsers
改變視圖值的格式,並更新的到模型($viewValue
-> $modelValue
),與之相對的是 $formatters
,恰好反過來。
$validators
用來添加同步驗證器
$asyncValidators
用來添加異步驗證器
$error
沒有經過的驗證器名稱及對應的錯誤信息
$valid
表單項是否都經過驗證,都經過時爲 true,與之相對的是 $invalid
$touched
表單項是否被訪問過,若是得到過焦點,在失去時該值爲 true,與之相對的是 $untouched
$dirty
表示用戶是否和表單項交互過(好比輸入一些東西),只要有任何改變,該值爲 true,與之相對的是 $pristine
$render
定義視圖具體的渲染方式
$setViewValue
設置視圖值(須要手動觸發一個 $digest
),使用場景是在自定義指令中監聽自定義事件(好比使用具備回調的 jQuery 插件)
在 ngModelController
中講到,AngularJS 1.3 提供了驗證器管道,同步驗證只須要加到 $validators
上便可。
好比,有這樣一個常見的需求,對一個必填的名稱表單項,要求只能輸入中英文,最小長度爲2位字符,那麼能夠這樣實現。
指令:
app.directive('nameCheck', nameCheck); nameCheck.$inject = ['$http', '$q']; function nameCheck($http, $q){ var NAME_REG = /^[a-zA-Z\u4e00-\u9fa5]+$/; return { restrict: 'A', require: 'ngModel', link:function($scope,element,attrs,ctrl){ // 同步驗證 ctrl.$validators.char = function(modelValue, viewValue) { var value = modelValue || viewValue; if(!NAME_REG.test(value)){ return false; } return true; }; // 異步驗證 ctrl.$asyncValidators.exist = function(modelValue, viewValue){ var value = modelValue || viewValue; var deferred = $q.defer(); $http.get('api/users/' + value).then(function(res) { if(res.data.isExist){ deferred.reject(false); } deferred.resolve(true); }) return deferred.promise; } } } }
主頁面:
<form name="myForm"> <div class="form-group"> <input type="text" name="username" ng-model="username" class="form-control" name-check minlength="2" required> <span ng-messages="myForm.username.$error" ng-messages-include="error.html" ng-show="myForm.username.$touched"> </span> </div> </form>
錯誤信息頁面:
<span ng-message="required">必填</span> <span ng-message="char">非法字符</span> <span ng-message="minlength">過短了</span> <span ng-message="exist">名稱已存在</span>
ng-messages
是 AngularJS 1.3 提供的一個用來加強模版顯示的模塊,主要用在處理複雜的錯誤信息。
在之前的版本中,若是想處理錯誤信息的顯示,可能須要定義一堆 code
再結合複雜的 ng-if
語句來實現。並且在輸入同時知足多條錯誤規則的狀況下,沒法控制錯誤信息顯示的優先級。這些,使用 ng-messages
能夠完美解決。
引入 angular-messages.js
添加依賴:angular.module('app', ['ngMessages'])
有兩種使用方法,一是將 ng-messages
看成屬性指令使用:
<form name="myForm"> <input type="text" ng-model="field" name="myField" required minlength="5" /> <div ng-messages="myForm.myField.$error"> <div ng-message="required">必填</div> <div ng-message="minlength">長度不夠</div> </div> </form>
這樣會按照各個錯誤信息書寫的前後順序進行單一顯示,若是想同時顯示全部的錯誤信息,加個 ng-messages-multiple
:
<div ng-messages="myForm.myField.$error" ng-messages-multiple></div>
另外一種是將 ng-messages
看成元素指令使用:
<ng-messages for="myForm.myField.$error"> <ng-message when="required">必填</ng-message> <ng-message when="minlength">長度不夠</ng-message> </ng-messages>
若是不少表單項的錯誤提示信息都同樣,也能夠把錯誤信息放在模版裏,使用 ng-messages-include
指令來引用:
<div ng-messages="myForm.username.$error" ng-messages-include="validateTemplate/error.html"> </div>
錯誤模版文件:
<div ng-message="required">必填</div> <div ng-message="minlength">長度不夠</div>
更詳細的使用辦法直接看 angular-messages.js
源文件裏面的註釋便可。