<input type="text" ng-model='li' fv> /* 要使用link的第四个参数有两个必要条件 1 require存在 2 必须以属性或类名的方式存在于一个input标签中,并且该标签有ng-model属性; */ app.directive('fv', function(){ return { restrict: 'EA', require: 'ngModel', link: function(scope, ele, attr, ngmodel){ console.info('lifei',ngmodel); } } })
一下是输出的ngModel里面的内容
<form name='myForm'>
<input type="text" name='li1' ng-model="lifei1">
<input type="text" name="li2" pwd-match='myForm.li1' ng-model='lifei2'>
</form>
//判断两次输入的密码是否相同
app.directive('myPwdMatch', [function(){ return {
//如果用link的第四个参数ctrl,必须有require:'ngModel',和类型必须是属性 restrict: "A", require: 'ngModel', link: function(scope,element,attrs,ctrl){
//attrs.myPwdMatch的属性值是formName.input1Name字符串,用scope.$eval()来解析字符串,获取对应的input1Name对象 var tageCtrl = scope.$eval(attrs.myPwdMatch);
//添加自定义表单验证的合法性 tageCtrl.$parsers.push(function(viewValue){
//设置当前input的pwdmatch的合法性,如果input1的value值 等于当前input的value值,认为他合法 ctrl.$setValidity('pwdmatch', viewValue == ctrl.$viewValue); return viewValue; });
//当前input添加表单验证的合法性 ctrl.$parsers.push(function(viewValue){ if(viewValue == tageCtrl.$viewValue){ ctrl.$setValidity('pwdmatch', true); return viewValue; } else{ ctrl.$setValidity('pwdmatch', false); return undefined; } }); } }; }]);
也就是说: $validators和$asyncValidators这两个管道是$parsers管道函数数组里面的其中两个比较特殊的管道;
*5. $validators
一个json对象.
{ validateName: function(modelValue,viewValue){ return ... } }
当$setViewValue(value)被赋值给$modelValue之前,会经过$parsers管道,经过$parsers管道时,就会经过这个$validators管道.其中validateName是验证的名字,函数是这个验证的方法,其中的参数modelValue和viewValue就是$modelValue和$viewValue,如果返回值是true,则通过validateName
验证,如果返回值是false,则没有通过validateName验证,如果没有通过validateName验证,$error.validateName就会为true.这就是angular内部验证表单项的原理.
eg: 自定义一个验证规则,输入内容中必须包含数字
<div class="alert alert-danger" role="alert" ng-show="myForm.myWidget.$error.validCharacters"> <strong>Oh!</strong> 不符合自定义的验证规则! </div>
ngModel.$validators.validCharacters = function(modelValue, viewValue) { var value = modelValue || viewValue; return /[0-9]+/.test(value); };
*6.$asyncValidators
一个json对象.用来处理异步验证(比如一个http请求).
{ validateName: function(modelValue,viewValue){ return promise } }
其中validateName是验证的名字,函数是这个验证的方法,其中的参数modelValue和viewValue就是$modelValue和$viewValue,返回值必须是一个promise对象,如果这个promise对象传递给它下一个.then方法失败通知,则不通过validateName验证,如果这个promise对象传递给它下一个.then方法成功通知,则表示通过validateName验证.当异步验证开始执行的时候,所有的异步验证都是平行并发的.只有当所有的验证都通过时,数据模型才会被同步更新.只要有一个异步验证没有完成,这个验证名就会被放到ngModelController的$pending属性中.另外,所有的异步验证都只会在所有的同步验证通过以后才开始.
核心代码:
<input validate-name type="text" name="myWidget" ng-model="userContent" ng-model-options="{updateOn:'blur'}" class="form-control" required uniqueUsername> <div class="alert alert-danger" role="alert" ng-show="myForm.myWidget.$error.uniqueUsername"> <strong>Oh!</strong> 已经存在的用户名! </div>
app.directive('validateName',function($http,$q){ return { restrict:'A', require:'?^ngModel', link:function(scope,iele,iattr,ctrl){ ctrl.$asyncValidators.uniqueUsername = function(modelValue, viewValue) { var value = modelValue || viewValue; // 异步验证用户名是否已经存在 return $http.get('/api/users/' + value). then(function resolved(res) { if(res.data){ //用户名已经存在,验证失败,给下一个promise传递失败通知. return $q.reject('res.data'); } else { //用户名不存在,验证成功. return true } }, function rejected() { //请求失败 }) }; } } });
一个指令用于异步验证是否重命名:
/*异步验证是否重命名 * 例子: <input type="text" name="name" ng-model="form.name" create-head='{"url":"app_name/used","param":"app_name={value}"}'/> 1 自定义验证: require,属性 1 restrict必须是属性,requre必须是'ngModel' 2 进行异步验证设置 $asyncValidators = {验证名: 验证函数} 2 获取请求的url,用于ajax请求 1 用先把input标签上的createHead属性的json字符串获取 2 再用angular.formJson()解析成json对象 3 再用string.replace(string,value),把占位符"{value}" 替换成input的modelValue值(scope上的值) 4 用commonService来拼接url 3 创建一个defered对象,用来返回状态 1 用var a = $q.defer()创建 2 a.reject()表示拒绝 3 a.resolve()表示成功 4 $http请求 1 method,url,headers 2 返回的是一个promise对象 5 分情况验证 1 如果成功,说明找到了,命名重复,验证不通过,返回a.reject(); 2 如果404,说明没找到了,命名不重复,验证通过,返回a.resolve(); 3 如果是其他情况,不能确定,是否重命名,按验证不通过算,赶回a.reject(); 6 返回一个promise对象 * */ app.directive("createHead", ["$q", "$http", "$cookies", "AppConfig", "commonService", function($q, $http, $cookies, AppConfig, commonService){ return{ restrict:"A", require:"ngModel", scope:{ version:"=" }, link:function(scope,ele,attrs,ctl){ console.info("ctrl",ctl); //格式demo: create-head='{"url":"app_name/used","param":"app_name={value}"}' ctl.$asyncValidators.checkasync = function(modelValue,viewValue){ var d = $q.defer(); //angular.formJson()方法可以把json字符串解析成json对象; var _a = angular.fromJson(attrs.createHead); _a.url = _a.url.replace("{value}",modelValue); if(_a.param){ _a.param = _a.param.replace("{value}",modelValue); } $http({ method:"HEAD", url:commonService.getServerAuthUrl(_a.url,_a.param?_a.param:null), headers:{ "Authorization": $cookies.get("token") } }).then(function(e){ //200 已存在 d.reject(); },function(e){ if(e.status==404){ //不存在 d.resolve(); } else{ d.reject(); } }); return d.promise; }; } }; }]);