自定义表单验证

时间:2021-06-30 20:36:39
  <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里面的内容
  1. NgModelController
    1. $asyncValidators:Object     异步验证
    2. $commitViewValue:()
    3. $dirty:false                                  是否修改
    4. $error:Object                                错误
    5. $formatters:Array[1]                      数据格式化的管道函数数组
    6. $invalid:false                                是否不合法
    7. $isEmpty:(value)                               是否是空
    8. $modelValue:undefined                     当前的valud值
    9. $name:""                                                                               input的name
    10. $options:null 
    11. $parsers:Array[0]                                                                 设置表单合法性的管道函数数组
    12. $pending:undefined
    13. $pristine:true
    14. $render:()
    15. $rollbackViewValue:()
    16. $setDirty:()                                                                          设置是否已修改
    17. $setPristine:()
    18. $setTouched:()
    19. $setUntouched:()
    20. $setValidity:setValidity(validationErrorKey, state, controller)         设置表单的某一验证的合法性
    21. $setViewValue:(value, trigger)                         设置valud值
    22. $touched:false
    23. $untouched:true
    24. $valid:true                                                验证时候合法
    25. $validate:()
    26. $validators:Object                                  同步验证
    27. $viewChangeListeners:Array[0]               当value值改变时,执行的管道函数数组
    28. $viewValue:undefined               当前input的ng-model的值
    29. __proto__:Object

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