標籤:準備工作 form 使用者 優先 clu put 訪問 ini $scope
在使用 AngularJS 進行開發的時候,表單填寫是一個很常見的需求,而表單驗證又是比較讓人頭疼的部分,本文對此做一個總結。
在 Angular 的視圖中使用的 form 已經不是 HTML 中的普通 form 了,而是一個被 Angular 封裝過的指令。它可以完成普通 form 無法實現的功能,比如 form 嵌套,而且內建強大的驗證功能。
Angular 在對錶單進行校正的時候會使用 ngModelController 上的屬性,如果不設定 ng-model,則 Angular 無法知道 form.$invalid 這個值是否為真。後面在自訂驗證有對它的介紹。
本文在對錶單的驗證時使用了 ng-messages,在文章最後也有對它的介紹。
本文涉及到的源碼在 這裡,實現效果在 這裡。
原生表單驗證
在 form 層面,可以使用 ng-disabled 來控制提交按鈕的狀態,在 form 表單項全部驗證通過前不可點擊,下面介紹一下通用的表單項驗證選項。
input 驗證選項
AngularJS 的 input 標籤 內建的驗證選項有以下這些。
<input ng-model="" [name=""] [required=""] [ng-required=""] [ng-minlength=""] [ng-maxlength=""] [ng-pattern=""] [ng-change=""]>...</input>
a. 必填
<input type="text" name="myName" ng-model="username" required />
使用 ng-required 可以根據後面運算式的值設定是否 required 。
在不滿足 required 時 form.myName.$error 為 {required: true} 。
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 文檔。
CSS Classes
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 屬性的執行個體了。
ngModelController
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>
ngMessages
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 源檔案裡面的注釋即可。
Angular表單驗證