雖然我不是前端程序員,但明白前端做好驗證是多麼重要。
因為這樣後端就可以多喘口氣了,而且相比後端什麼的果然還是前端可以提高用戶的幸福感。
AngularJS提供了很方便的表單驗證功能,在此記錄一番。
首先從下面這段代碼開始
代碼如下:
<form ng-app="myApp" ng-controller="validationController" name="mainForm" novalidate>
<p>Email:
<input type="email" name="email" ng-model="email" required>
<span style="color:red" ng-show="mainForm.email.$dirty && mainForm.email.$invalid">
<span ng-show="mainForm.email.$error.required">Email is required.</span>
<span ng-show="mainForm.email.$error.email">Invalid email address.</span>
</span>
</p>
<p>
<input type="submit" ng-disabled="mainForm.$invalid">
</p>
</form>
<script>
angular.module('myApp',[])
.controller('validationController', ['$scope',function($scope) {
$scope.user = 'Kavlez';
$scope.email = 'sweet_dreams@aliyun.com';
}]);
</script>
input標簽的一些驗證選項,通常和HTML5標記搭配使用。
必填
<input type="text" required />
長度
使用指令ng-minlength/ng-maxlength
<input type="text" ng-minlength="5" />
特定格式
例如電子郵件、URL、數字,將type設置為相應類型即可,例如:
代碼如下:
<input type="email" name="email" ng-model="user.email" />
<input type="number" name="age" ng-model="user.age" />
<input type="url" name="homepage" ng-model="user.facebook_url" />
模式匹配
使用指令ng-pattern,例如:
代碼如下:
<input type="text" ng-pattern="[a-z]" />
表單屬性,通過這些屬性可以更容易地對表單進行操作
pristine/dirty
表示是否已修改,例如
代碼如下:
<form name="mainForm" ng-controller="orderController">
<input type="email" name="userEmail" ng-model="myEmail" />
{{mainForm.userEmail.$pristine}}
{{mainForm.userEmail.$dirty}}
</form>
以formName.fieldName.$pristine方式訪問,input必須有ng-model聲明。
代碼如下:
valid/invalid
表示是否通過驗證。
代碼如下:
$error
表單驗證信息,驗證不通過時返回相應信息。
AngularJS為表單狀態提供了相應地css class
代碼如下:
.ng-pristine
.ng-dirty
.ng-valid
.ng-invalid
例如,讓驗證通過為綠色,失敗為紅色:
代碼如下:
input.ng-valid {
color: green;
}
input.ng-invalid {
color: green;
}
給出的例子中僅僅是一個email的驗證就寫了這麼多,如果再加幾個field,再加幾種不同的提示,再加上幾個事件,代碼會變得雜亂不堪。
事實上並不推薦這樣做,我們有更好的方法。
就是使用angular-messages.js
首先,不要忘了這兩步
代碼如下:
<script src="angular-messages.js"></script>
angular.module('myApp', ['ngMessages'])
好,先用ng-messages和ng-message替換掉那些重復的東西,上面的例子變成:
代碼如下:
<form ng-controller="validationController" name="mainForm" >
<p>Email:
<input
type="email" name="email" ng-model="myEmail" ng-minlength="3" ng-maxlength="50" required />
<div style="color:red" ng-messages="mainForm.email.$error" ng-messages-multiple>
<p class="error" ng-message="required">Email is required.</p>
<p class="error" ng-message="email">Invalid email address.</p>
<p class="error" ng-message="minlength">min length 10</p>
<p class="error" ng-message="maxlength">max length 50</p>
</div>
</p>
<p>
<input type="submit" ng-disabled="mainForm.$invalid" />
</p>
</form>
功能上沒有任何變化,只是把重復的代碼全部去掉了。
注意區分ng-messasges和ng-message,有沒有感覺有點像with()? 後面的ng-messages-multiple,這裡用作同時讓多個提示出現。
但這樣仍然不夠好,就算省去了ng-message中的內容,但是多個field中都存在required驗證時仍然會有重復。
而且,如果不同頁面中的表單都涉及到相同的內容時重復的驗證提示會越來越多。
為了解決這個問題,我們可以使用ng-messages-include指令。
該指令用來引用模板,比如上面的例子變為:
代碼如下:
<form ng-controller="validationController" name="mainForm" >
<p>Email:
<input
type="email" name="email" ng-model="myEmail" ng-minlength="3" ng-maxlength="50" required />
<div style="color:red" ng-messages="mainForm.email.$error" ng-messages-multiple ng-messages-include="validateTemplate/email.html">
</div>
</p>
<p>
<input type="submit" ng-disabled="mainForm.$invalid" />
</p>
</form>
並不復雜,我們再加點東西。
為了讓提示更友好(?)一些,我們試試實現光標離開後出現提示的效果。
這時候用指令(directive)會方便很多,在這裡先涉及一點和指令相關的內容。
先運行起來再說:
代碼如下:
var myApp = angular.module('myApp',[])
.controller('validationController', ['$scope',function($scope) {
$scope.user = 'Kavlez';
$scope.email = 'sweet_dreams@aliyun.com';
}])
.directive('hintOnBlur', [function() {
return {
require: 'ngModel',
link: function(scope, element, attrs, ctrl) {
ctrl.focused = false;
element.bind('focus', function(evt) {
scope.$apply(function() {ctrl.focused = true;});
}).bind('blur', function(evt) {
scope.$apply(function() {ctrl.focused = false;});
});
}
}
}]);
此處我們用focused來判斷光標是否在某個屬性上,當使用了hintOnBlur指令的對象上發生focus或blur事件時focused的狀態發生變化。
表單也跟著改變一下,使用方法如下:
代碼如下:
<form ng-controller="validationController" name="mainForm" >
<p>Email:
<input type="email" name="email" ng-model="myEmail" ng-minlength="3" ng-maxlength="50" required hint-on-blur />
<div style="color:red" ng-messages="mainForm.email.$error" ng-show="!mainForm.email.focused" ng-messages-multiple ng-messages-include="validateTemplate/email.html">
</div>
</p>
<p>
<input type="submit" ng-disabled="mainForm.$invalid" />
</p>
</form>
在ng-show中再加入對focused的判斷,false時出現提示。
現在看起來像那麼回事了。
自定義驗證方式與有效性(validity),這個也用到指令(directive)。
驗證填寫的email是否已占用,這裡簡單模擬一下:
代碼如下:
.directive('isAlreadyTaken', function() {
return {
require: 'ngModel',
link: function(scope, ele, attrs, ctrl) {
ctrl.$parsers.push(function(val) {
ctrl.$setValidity('emailAvailable', false);
var emailTable = [
'K@gmail.com',
'a@gmail.com',
'v@gmail.com',
'l@gmail.com',
'e@gmail.com',
'z@gmail.com'];
for (var i=0;i<emailTable.length;i+=1)
if(val==emailTable[i])
return;
ctrl.$setValidity('emailAvailable', true);
return val;
})
}
}
})
Input元素中加上is-already-taken屬性,並且再加一個ng-message:
代碼如下:
<p class="error" ng-message="emailAvailable">Already taken! try other email addresses!</p>