以前說過了angular是如何給表單的數據進行基本的,經常使用的驗證的:angular學習筆記(二十)-表單驗證css
可是在實際工做中,這些驗證是遠遠不夠的,不少時候咱們須要自定義一些驗證規則,以及一些異步,須要向後臺發送請求的驗證.html
這篇文章就來說解,如何自定義驗證規則.node
同時,這篇文章仍是angular指令中使用ngModelController中關於 $validators 屬性和 $asyncValidators 和 $pending 屬性的詳細講解.git
首先,須要自定義指令,設置require屬性爲'?^ngModel',在指令的link函數中經過第四個參數ctrl,獲取到ngModelController這個東西.github
ngModelController實例有兩個對象,一個是 $validators對象,一個是 $asyncValidators對象.當咱們須要添加自定義的同步驗證規則時,使用$validators對象,當咱們須要添加自定義的異步驗證規則時,使用$asyncValidators對象.express
經過栗子來講明:bootstrap
html:api
<!DOCTYPE html> <html ng-app="customControl"> <head> <title>asyncValidators</title> <meta charset="utf-8"> <script src="angular-1.3.2.js"></script> <script src="script.js"></script> <link type="text/css" href="bootstrap.css" rel="stylesheet" /> <style> *{font-family: 'MICROSOFT YAHEI'} </style> </head> <body> <div class="container" ng-controller="ctrl"> <div class="page-header"> <h1>ngModelController- <small>asyncValidators實現異步驗證表單</small></h1> </div> <form role="form" name="myForm"> <div class="form-group"> <input validate-name type="text" name="myWidget" ng-model="userContent" ng-model-options="{updateOn:'blur'}" class="form-control" required> </div> <div class="alert alert-danger" role="alert" ng-show="myForm.myWidget.$error.required"> <strong>Oh!</strong> 必填! </div> <div class="alert alert-danger" role="alert" ng-show="myForm.myWidget.$error.validCharacters"> <strong>Oh!</strong> 不符合自定義的驗證規則! </div> <div class="alert alert-danger" role="alert" ng-show="myForm.myWidget.$error.uniqueUsername"> <strong>Oh!</strong> 已經存在的用戶名! </div> </form> <div class="panel panel-primary"> <div class="panel-heading"> <h3 class="panel-title">用戶名:</h3> </div> <div class="panel-body"> {{userContent}} </div> </div> <div class="panel panel-primary"> <div class="panel-heading"> <h3 class="panel-title">正在異步驗證中:</h3> </div> <div class="panel-body"> {{myForm.myWidget.$pending}} </div> </div> </div> </body> </html>
這段html裏,input元素使用了validate-name這個指令,後面在js中咱們會經過這個指令來給它添加驗證.注意元素必需要有ng-model屬性,不然也沒有什麼意義了...promise
這個指令咱們共驗證三項,且在元素失去焦點的時候進行驗證:app
1.required : ng內置的的驗證,須要在指令的最後添加required屬性. 而後本身指令裏什麼也不用寫,就能夠驗證它是否爲空了.
2.validCharacters: 自定義的一個同步驗證規則,驗證輸入的內容是否包含'bunny'字符串,自定義的驗證不須要在指令最後添加validCharacters屬性
3.uniqueUsername: 自定義的一個異步驗證規則,驗證輸入的用戶名是否已經被註冊,一樣,自定義的規則不須要在指令的最後添加uniqueUsername屬性
而後來看js代碼:
var app = angular.module('customControl',[]); app.controller('ctrl',function($scope){ }); app.directive('validateName',function($http,$q){ return { restrict:'A', require:'?^ngModel', link:function(scope,iele,iattr,ctrl){ ctrl.$validators.validCharacters = function(modelValue, viewValue) { var value = modelValue || viewValue; return value ? value.indexOf('bunny')!==-1 : true }; ctrl.$asyncValidators.uniqueUsername = function(modelValue, viewValue) { var value = modelValue || viewValue; // Lookup user by username return $http.get('/api/users/' + value). then(function resolved(res) { if(res.data){ //用戶名已經存在,驗證失敗,給下一個promise傳遞失敗通知. return $q.reject('res.data'); } else { //用戶名不存在,驗證成功. return true } }, function rejected() { }) }; } } });
先說 validCharacters 驗證: 咱們給ctrl(也就是ngModelController的實例)的$validators屬性添加了validCharacters屬性,它的屬性值爲一個函數,函數接受兩個參數modelValue和viewValue,這兩個參數具體分別表明什麼,請入angular指令中使用ngModelController查看,總之,這裏能夠認爲就是input的value值.而後咱們經過這個自定義的函數的返回值來肯定是否經過驗證,若是是true,則經過驗證,若是是false,則不經過驗證,在不經過驗證的時候,$error.validCharacters就會爲true.
同理,來看uniqueUsername 驗證:咱們給ctrl的$asyncValidators屬性添加了uniqueUsername屬性,它的屬性值爲一個函數,函數接受的參數也同上,而後咱們經過$http發送請求來驗證用戶名是否存在:
node代碼:
var express = require('express'); var app = express(); app.use(express.static(__dirname+'')); app.use(express.bodyParser()); app.use(express.methodOverride()); var names = [ 'code_bunny','mi_bunny','hua_bunny' ]; app.get('/api/users/:name',function(req,res){ setTimeout(function(){ var name = req.params.name; names.forEach(function(list){ if(name==list) { res.send(list); } else { res.end() } }); },1000); }); app.listen(9000);
咱們故意延遲了1000毫秒再給出響應,這樣,在等待響應的時間裏,咱們能夠看到myForm.myWidget.$pending發生的變化:
當獲得響應後,它就會變爲空.
因此,$pending屬性裏放置的是因此正在等待響應的異步驗證.
最重要的一點,$asyncValidators的驗證函數返回值好比是一個promise對象.根據這個promise對象發出的通知來決定驗證是成功仍是失敗.若是發出的是失敗通知,那麼它就是驗證失敗,好比這裏的$q.reject().若是發出的是成功經過,那麼他就是驗證成功,好比這裏的return false.
這裏要注意promise的用法:因爲$http.get()返回的promise,不管執行的是resolved函數仍是rejected函數,他發送給下一個promise的通知老是成功的,因此爲了發送失敗通知,必須使用$q.reject().
另外,我原本想嘗試若是能搜索到用戶名,則返回搜索到的用戶名,若是不能,則不返回,讓它接收到404狀態,而後調用rejected函數,可是沒能成功,由於若是不返回,它會請求很長一段時間纔算請求失敗,而不是一旦發現找不到就馬上算請求失敗了.因此這裏仍是根據搜索結果返回不一樣值來進行判斷.
完整代碼: https://github.com/OOP-Code-Bunny/angular/tree/master/ngModelController/asyncValidators