<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;
};
}
};
}]);