AngularJS - 表单验证
虽然我不是前端程序员,但明白前端做好验证是多么重要。
因为这样后端就可以多喘口气了,而且相比后端什么的果然还是前端可以提高用户的幸福感。
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>