之前说过了angular是如何给表单的数据进行基本的,常用的验证的:
但是在实际工作中,这些验证是远远不够的,很多时候我们需要自定义一些验证规则,以及一些异步,需要向后台发送请求的验证.
这篇文章就来讲解,如何自定义验证规则.
同时,这篇文章还是中关于 $validators 属性和 $asyncValidators 和 $pending 属性的详细讲解.
首先,需要自定义指令,设置require属性为'?^ngModel',在指令的link函数中通过第四个参数ctrl,获取到ngModelController这个东西.
ngModelController实例有两个对象,一个是 $validators对象,一个是 $asyncValidators对象.当我们需要添加自定义的同步验证规则时,使用$validators对象,当我们需要添加自定义的异步验证规则时,使用$asyncValidators对象.
通过栗子来说明:
html:
asyncValidators ngModelController- asyncValidators实现异步验证表单
用户名:
{ {userContent}}正在异步验证中:
{ {myForm.myWidget.$pending}}
这段html里,input元素使用了validate-name这个指令,后面在js中我们会通过这个指令来给它添加验证.注意元素必须要有ng-model属性,否则也没有什么意义了...
这个指令我们共验证三项,且在元素失去焦点的时候进行验证:
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,这两个参数具体分别代表什么,请入查看,总之,这里可以认为就是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函数,但是没能成功,因为如果不返回,它会请求很长一段时间才算请求失败,而不是一旦发现找不到就立刻算请求失败了.所以这里还是根据搜索结果返回不同值来进行判断.
完整代码: