表单和验证是AngularJS中复杂的组件之一。用AngularJS默认的方式来写,不是特别好,不简洁。
在AngualrJS1.3发布前,表单验证必须以这种方式编写。
如今随着AngularJS1.3的发布,AngularJS核心做了一个升级。它不再需要基于一个详细的表达式状态创建元素显示或者隐藏。
HTML
<form name="signup_form" novalidate ng-submit="signupForm()"
ng-controller="signupController">
<fieldset>
<legend>Signup</legend>
<div class="row">
<div class="large-12 columns">
<label>Your name</label>
<input type="text" placeholder="Name" name="name" ng-model="signup.name"
ng-minlength=3 ng-maxlength=20 required />
<div class="error" ng-show="signup_form.name.$dirty && signup_form.name.
$invalid && signup_form.submitted">
<small class="error" ng-show="signup_form.name.$error.required">
Your name is required.</small>
<small class="error" ng-show="signup_form.name.$error.minlength">
Your name is required to be at least 3 characters</small>
<small class="error" ng-show="signup_form.name.$error.maxlength">
Your name cannot be longer than 20 characters </small>
</div>
</div>
</div>
<button type="submit">Submit</button>
</fieldset>
</form>
本质上这一功能会检查错误对象的状态发生了变化,此外,我们不得到了站点中每个表单需要的
很多额外的重复的标记。这显然不是一个理想的解决方案。
从1.3开始,Angualr中新增一个ngMessage指令。
$ bower install --save angular-messages
还需要将angular-messages.js这个JavaScript引入我们的主HTML中:<script type="text/javascript" src="bower_components/angular-messages/angular-messages.js"> </script>
我们还要告诉Angular将ngMessages作为应用程序的依赖模块引入,就像这样:
angular.module('myApp', ['ngMessages']);
现在,我们已经安装了ngMessage,然后可以马上开始使用它了。使用前面的例子作为基础,你可以移除ng-show,然后
使用ngMessage的一个更简洁的实现替换它。
<form name="signup_form" novalidate ng-submit="signupForm()"
ng-controller="signupController">
<label>Your name</label>
<input type="text" placeholder="Name" name="name" ng-model="signup.name" ng-minlength=
3 ng-maxlength=20 required />
<div class="error" ng-messages="signup_form.name.$error">
<div ng-message="required">Make sure you enter your name</div>
<div ng-message="minlength">Your name must be at least 3 characters</div>
<div ng-message="maxlength">Your name cannot be longer than 20 characters</div>
</div>
<button type="submit">Submit</button>
</form>
然而对于这个实现,一次只会显示一个错误信息。如果我们想要更新这个实现同时显示所有的错误将会怎样?
也是很容易实现的。只需要在ng-message指令旁边使用ng-message-multiple
属性即可。
<div class="error" ng-messages="signup_form.name.$error" ng-messages-multiple>
<div ng-message="required"> sure you enter your name</div>
<div ng-message="minlength">Your name must be at least 3 characters</div>
<div ng-message="maxlength">Your name cannot be longer than 20 characters</div>
</div>
很多时候这些信息之间非常相似。我们可以将它们保存到模块中从而减少麻烦。而不是重新输入每个字段的错误信息。
<!-- In templates/errors.html -->
<div ng-message="required">This field is required</div>
<div ng-message="minlength">The field must be at least 3 characters</div>
<div ng-message="maxlength">The field cannot be longer than 20 characters</div>
然后我们可以通过在视图中使用ng-messages-include属性引入这个模版来改进这个表单:
<div class+'error' ng-messages="signup_form.name.$error"
ng-messages-include="templates/errors.html">
</div>
有时,你可能希望为不同的字段自定义错误信息。没问题,你可以在这个指令内简单地插入一个自定义错误信息。
由于ngMessages涉及ngMessages容器中错误列表的顺序,我们可以通过在这个指令中列出自定义错误信息的方式覆盖它们。
<div class="error" ng-messages="signup_form.name.$error"
ng-messages-include="templates/errors.html">
<!-- 除了minlength会被覆盖之外,其他每个信息都会保持不变-->
</div>
此外,甚至还可以为自定义验证创建自定义消息。可以通过修改模型的$parsers
链做到这一点。
例如,比方说我们想要创建一个自定义验证器验证用户名在一个注册表单中是否有效:
对于ngModel,你可以添加可以使用ngMessage指令显示/隐藏的自定义信息。还可以添加可以使用ngMessage
指令检查的带有自定义的消息的指令。例如,改变前面使用ngMessages的例子。
HTML
<form name="signup_form" novalidate ng-submit="signupForm()" ng-controller="signupController"
ensure-unique="/api/checkUsername.json">
<label>
Your name
</label>
<input type="text" placeholder="Username" name="username" ng-model="signup.username"
ng-minlength=3 ng-maxlength=20 required />
<div class="error" ng-messages="signup_form.username.$error">
<div ng-message="required">
Make sure you enter your username
</div>
<div ng-message="checkingAvailability">
Checking...
</div>
<div ng-message="usernameAvailablity">
The username has already been taken. Please choose another
</div>
</div>
<button type="submit">
Submit
</button>
</form>
在这个用法中,我们检查了错误信息的自定义属性。为了添加自定义错误信息,我们将会把它们应用到自定义ensureUnique指令的ngModel中。
JAVASCRIPT
app.directive('ensureUnique', function($http) {
return {
require: 'ngModel',
link: function(scope, ele, attrs, ctrl) {
var url = attrs.ensureUnique;
ctrl.$parsers.push(function(val) {
if (!val || val.length === 0) {
return;
}
ngModel.$setValidity('checkingAvailability', true);
ngModel.$setValidity('usernameAvailablity', false);
$http({
method: 'GET',
url: url,
params: {
username: val
}
}).success(function() {
ngModel
.$setValidity('checkingAvailability', false);
ngModel
.$setValidity('usernameAvailablity', true);
})['catch'](function() {
ngModel
.$setValidity('checkingAvailability', false);
ngModel
.$setValidity('usernameAvailablity', false);
});
return val;
})
}
}
});