首页 > 代码库 > angular 输入框实现自定义验证

angular 输入框实现自定义验证

此插件使用angular.js、JQuery实现。(jQuery的引入需在angular 之前)

  用户可以 在输入框输入数据后验证 必填项、整数型、浮点型验证。

  如果在form 里面的输入框验证,可以点击 提交按钮后,实现 必填项验证。

效果图如下:

  技术分享

 

(1)验证未通过时,背景标红等样式为  

技术分享
 input.ng-invalid, select.ng-invalid {            background-color: #ee82ee !important;            border: 1px solid #CCC;        }        .qtip {            position: absolute;            max-width: 260px;            display: none;            min-width: 50px;            font-size: 10.5px;            line-height: 12px;            direction: ltr;        }        .qtip-content {            position: relative;            padding: 5px 9px;            overflow: hidden;            text-align: left;            word-wrap: break-word;        }        .qtip-rounded, .qtip-tipsy {            -moz-border-radius: 5px;            -webkit-border-radius: 5px;            border-radius: 5px;        }        .qtipmodal-ie6fix {            position: absolute !important;        }        .box-shadow-tips {            background-color: #F63;            border-color: #F5A88F;            color: white;            -moz-box-shadow: 2px 2px 2px #969696;            -webkit-box-shaow: 2px 2px 2px #969696;            box-shadow: 2px 2px 2px #969696;        }
背景标红等样式

  因为angular.js 内置验证未通过时,会自动为 标签 增加 .ng-invalid 样式,因为这里重写此样式

  input.ng-invalid, select.ng-invalid {
  background-color: #ee82ee !important;
  border: 1px solid #CCC;
  } 
(2)HTML 代码如下
<body ng-app="myApp"><form name="baseInfoForm">    <div ng-controller="testCtrl">        <input type="text" ng-model="age" my-valid="r"><br>        <input type="text" ng-model="name" my-valid="int fn:certCheck"><br>        <input type="button" value="提交" ng-click="submit()">    </div></form></body>

 

(3)此插件使用 directive myValid 实现

技术分享
app.directive(‘myValid‘, [‘$parse‘, ‘uiTipsFactory‘, ‘uiValidFactory‘, function ($parse, tips, valid) {        var uiValidAttrIdName = ‘ui-valid-id‘;        return {            restrict: ‘A‘,            require: ‘ngModel‘,            link: function (scope, el, attrs, ctrl) {                var validId = el.attr(uiValidAttrIdName);                if (!validId) {                    validId = Math.guid();                    el.attr(uiValidAttrIdName, validId);                }                var getRules = function () {                    return attrs.myValid;                };                var lastOldRules;                var validFn = function (value, oldRules) {                    var sp = ‘_‘;                    var rules = getRules();                    var r = valid.check(value, rules, scope, attrs.uiValidTips);                    if (lastOldRules && !oldRules) {                        oldRules = lastOldRules;                    }                    if (r.flag && oldRules) {                        rules = rules ? rules + ‘ ‘ + oldRules : oldRules;                    }                    if (rules) {                        var arrInner = rules.split(‘ ‘);                        var i = 0;                        for (; i < arrInner.length; i++) {                            var oneRule = arrInner[i];                            if (!oneRule.trim()) {                                continue;                            }                            ctrl.$setValidity(attrs.ngModel + sp + oneRule, r.flag ? true : oneRule != r.rule);                        }                    }                    if (!r.flag) {                        tips.on(el, r.msg);                    } else {                        tips.off(el);                    }                    return r.flag;                };                var init = function () {                    var rules = getRules();                    if (!rules) {                        return;                    }                    var parsers = ctrl.$parsers;                    if (parsers && parsers.length > 0) {                        parsers.clean();                    }                    parsers.unshift(function (value) {                        return validFn(value) ? value : undefined;                    });                };                scope.$watch(attrs.ngModel, function (newVal, oldVal) {                    if (newVal === oldVal) {                        return;                    }                    if (ctrl.$modelValue != undefined && (ctrl.$invalid || el.hasClass(‘ng-invalid‘))) {                        validFn(ctrl.$modelValue);                    }                });                scope.$watch(getRules, function (newRules, oldRules) {                    init();                    lastOldRules = oldRules;                    if (ctrl.$modelValue =http://www.mamicode.com/== undefined || ctrl.$modelValue === null) {                        var needValid = false;                        el.hasClass(‘ng-invalid‘);                        var isValNaN = ctrl.$viewValue !== ctrl.$viewValue;                        if (ctrl.$invalid || (ctrl.$viewValue !== undefined && !isValNaN)) {                            needValid = true;                        }                        if (needValid) {                            ctrl.$setViewValue(ctrl.$viewValue);                        }                    } else {                        if (!ctrl.$dirty && attrs.dirtyCheck) {                            console.log(‘----‘);                        } else {                            validFn(ctrl.$modelValue, oldRules);                        }                    }                });            }        }    }]);
directive--myValid

  通过 监听 attrs.ngModel,验证规则 rules ,ctrl.$parser 来实现 输入框内容改变的响应。

  一旦使用此directive,则动态为当前输入框添加ID,以便在 验证通过后,改变输入框的验证背景信息。

 

(4)验证逻辑处理 uiValidFactory

技术分享
app.factory(‘uiValidFactory‘, [‘$parse‘, ‘uiTipsFactory‘, function ($parse, tips) {        return {            check: function (val, rules, $scope, defaultTips, extendParam) {                if (!rules) {                    return {                        flag: true                    };                }                var rulesArr = rules.split(‘ ‘),                        isBlank = val === null || val === undefined || val === ‘‘ || (‘‘ + val === ‘‘);                //如果不是必填项 且没有输入值 则清除提示框                if ($.inArray(‘r‘, rulesArr) === -1 && isBlank) {                    return {                        flag: true                    }                }                var i = 0, len = rulesArr.length;                for (; i < len; i++) {                    var rule = rulesArr[i];                    if (!rule) {                        continue;                    }                    var flag = true;                    if (‘r‘ === rule) {                        //如果是必填项,有值 返回true                        flag = !isBlank;                    } else if (rule.contains(‘:‘)) {                        //如果校验规则是 fn:ctrl.certCheck                        flag = this.checkRule(val, rule.split(/:/), $scope, extendParam);                    } else {                        //校验 规则是 int 用正则匹配 数字 邮箱 长度                        var pat = this.pats[rule];                        if (pat instanceof RegExp) {                            if (angular.isString(val)) {                                flag = this.mat(val, pat);                            }                        } else if (angular.isFunction(pat)) {                            flag = pat(val);                        } else {                            flag = false;                        }                    }                    //这是干什么的呢                    if (angular.isString(flag)) {                        return {                            flag: false,                            msg: flag,                            rule: rule                        }                    }                    if (flag === false) {                        var msg = this.getMsg(rule, defaultTips) || this.getMsg(‘tips.valid‘);                        console.log(msg);                        return {                            flag: false,                            msg: msg,                            rule: rule                        }                    }                }                return {                    flag: true                }            },            checkRule: function (val, ruleArr, $scope, extendParam) {                //ruleArr fn:certCheck                var rule = ruleArr[0];                if (rule === ‘fn‘) {                    fnName = ruleArr[1];//指定被调函数的名字 certCheck                    var fn = $parse(fnName)($scope);                    if (!fn) {                        return true;                    }                    return fn.call($scope, val, extendParam);                } else {                    return true;                }            },            checkValidForm: function (formName) {                //只检查必填项                //使用属性筛选器 获得里面所有的元素                var formContext = $(‘form[name="{0}"],[ng-form="{0}"],[data-ng-form="{0}"]‘.format(formName)),                        validList = formContext.find(‘[my-valid]‘);//validList 不是数组,是伪数组                if (!validList.length) {                    return;                }                var that = this,                        validFlags = [];                validList.each(function () {                            var ele = $(this),                                    val = ele.val(),                                    ruleStr = ele.attr(‘my-valid‘);                            if (!ruleStr) {                                return true;                            }                            if (angular.isString(val)) {                                val = val.trim();                            }                            var validRules = ruleStr.split(‘ ‘);                            if ($.inArray(‘r‘, validRules) != -1 && !val) {                                var modelValue = http://www.mamicode.com/ele.attr(‘ng-model‘) || ele.attr(‘data-ng-model‘);                                validFlags.push(modelValue);                                tips.on(ele, that.getMsg(‘r‘));                            }                        }                );                return validFlags;            },            mat: function (val, pat) {                if (!pat) {                    return;                }                return pat.test(val);            }            ,            getMsg: function (rule, tips) {                tips = tips || ‘‘;                //可以在界面上直接写 tips                if (tips && tips.contains(‘:‘)) {                    return tips;                }                var msg = this.msgs[rule];                if (msg) {                    var params0 = tips.contains(‘:‘) ? tips.split(/:/)[0] : ‘‘;                    var params1 = ‘‘;                    if (rule.startsWith(‘min‘) || rule.startsWith(‘max‘)) {                        var ruleArr = rule.split(/:/);                        params1 = ruleArr[ruleArr.length - 1];                    }                    return msg.format(params0, params1);                } else {                }            }            ,            regPat: function (code, pat, msg) {                if (this.pat[code]) {                    return;                }                this.pats[code] = pat;                this.msgs[code] = msg;            }            ,            msgs: {                ‘r‘: ‘必填‘,                ‘int‘: ‘{0}必须为整数‘            }            ,            pats: {                ‘int‘: /^[\-\+]?([0-9]+)$/            }        }    }    ])    ;
uiValidFactory

       通过获取输入框 ele.myValid  验证规则,

   1、如果是必填,则返回 标红此输入框,鼠标移上,则显示 验证信息 “必填””。

   2、如果是整数、浮点型等验证,则通过 正则表达式进行验证。

      3、如果是最大(max)、最小(min),则自定义逻辑。

  4、如果是 fn 验证,则根据 对应controller中函数进行验证。

  5、用户点击提交按钮,则 判断是否必填项,验证不通过,对应元素背景标红。

 

(5) 验证不通过,提示Factory---uiTipsFactory

技术分享
app.factory(‘uiTipsFactory‘, function () {        return {            filterClass: function (ele, invalid) {                if (invalid) {                    //如果验证不通过                    ele.removeClass(‘ng-valid‘).removeClass(‘ng-pristine‘).addClass(‘ng-invalid‘).addClass(‘ng-dirty‘);                } else {                    ele.removeClass(‘ng-invalid‘).addClass(‘ng-valid‘);                }            },            on: function (ele, msg) {                var lastTip = ele.data(‘last-tip‘);                if (lastTip && lastTip === msg) {                    return;                }                ele.data(‘last-tip‘, msg);                this.filterClass(ele, true);                var offset = ele.offset();                if (!offset.top && !offset.left && ele.is(‘hidden‘)) {                    offset = ele.show().offset();                }                var id = ele.attr(‘ui-valid-id‘);                if (!id) {                    id = Math.guid();                    ele.attr(‘ui-valid-id‘, id);                }                if (id.contains(‘.‘)) {                    id = id.replace(/\./g, ‘_‘);                }                var top = offset.top,                        left = offset.left;                var getTips = function () {                    var _tip = $(‘#vtip_‘ + id);                    if (_tip.length) {                        _tip.html(msg).css({                            ‘display‘: ‘none‘,                            ‘top‘: top + ‘px‘,                            ‘left‘: left + ele.width() + 10 + ‘px‘                        });                    } else {                        var html = ‘<div id="vtip_‘ + id + ‘" class="vtip qtip  qtip-rounded box-shadow-tips">‘ +                                ‘<div class="qtip-content">‘ + msg + ‘</div>‘;                        $(html).css({                            ‘display‘: ‘none‘,                            ‘position‘: ‘absolute‘,                            ‘top‘: top + ‘px‘,                            ‘left‘: left + ele.width() + 10 + ‘px‘                        }).appendTo($(‘body‘));                    }                };                var bindTipsShow = function () {                    getTips();                    ele.unbind(‘mouseenter mouseleave‘).bind(‘mouseenter‘, function () {                        var _tip = $(‘#vtip_‘ + id);                        if (_tip.is(‘:hidden‘)) {                            _tip.show();                        }                    }).bind(‘mouseleave‘, function () {                        $(‘#vtip_‘ + id).hide();                    });                };                bindTipsShow();            },            off: function (ele) {                ele.data(‘last-tip‘, ‘‘);                this.filterClass(ele);                var id = ele.attr(‘ui-valid-id‘);                if (!id) {                    return;                }                if (id.contains(‘.‘)) {                    id = id.replace(/\./g, ‘_‘);                }                $(‘#vtip_‘ + id).remove();                ele.unbind(‘mouseenter mouseleave‘);            }        }    });
uiTipsFactory

   1、验证不通过,增加背景色,元素css处理如下

      ele.removeClass(‘ng-valid‘).removeClass(‘ng-pristine‘).addClass(‘ng-invalid‘).addClass(‘ng-dirty‘);

   验证通过,CSS处理如下
    
ele.removeClass(‘ng-invalid‘).addClass(‘ng-valid‘);
  2、背景提示语,则是在body上增加一个div层。

(6)其他相关代码
技术分享
 var app = angular.module(‘myApp‘, []);    app.controller(‘testCtrl‘, [‘$scope‘, ‘uiValidFactory‘, function ($scope, uiValidFactory) {                $scope.certCheck = function (val) {                    if (val > 32) {                        return "数字太大了";                    }                    return true;                };                $scope.submit = function () {                    if (!uiValidFactory.checkValidForm($scope.baseInfoForm.$name)) {                    }                };            }]    );    Math.guid = function () {        var a = "", b = 1;        for (; b <= 32; b++) {            var c = Math.floor(Math.random() * 16).toString(16);            a += c;            if (b === 8 || b === 12 || b === 16 || b === 20) {                a += ‘-‘;            }        }        return a;    };    String.prototype.contains = String.prototype.contains || function (a) {        return this.indexOf(a) != -1;    };    String.prototype.format = String.prototype.format || function () {        var a = Array.prototype.slice.call(arguments);        return this.replace(/\{(\d+)}/g, function (c, b) {            return a[b];        })    };
others

   整个代码如下:

技术分享
  1 <!DOCTYPE html>  2 <html>  3 <head lang="en">  4     <meta charset="UTF-8">  5     <title></title>  6     <script src="http://www.mamicode.com/jquery-1.11.1.js"></script>  7     <script src="http://www.mamicode.com/angular.js"></script>  8     <style type="text/css">  9  10         input.ng-invalid, select.ng-invalid { 11             background-color: #ee82ee !important; 12             border: 1px solid #CCC; 13         } 14  15         .qtip { 16             position: absolute; 17             max-width: 260px; 18             display: none; 19             min-width: 50px; 20             font-size: 10.5px; 21             line-height: 12px; 22             direction: ltr; 23         } 24  25         .qtip-content { 26             position: relative; 27             padding: 5px 9px; 28             overflow: hidden; 29             text-align: left; 30             word-wrap: break-word; 31         } 32  33         .qtip-rounded, .qtip-tipsy { 34             -moz-border-radius: 5px; 35             -webkit-border-radius: 5px; 36             border-radius: 5px; 37         } 38  39         .qtipmodal-ie6fix { 40             position: absolute !important; 41         } 42  43         .box-shadow-tips { 44             background-color: #F63; 45             border-color: #F5A88F; 46             color: white; 47             -moz-box-shadow: 2px 2px 2px #969696; 48             -webkit-box-shaow: 2px 2px 2px #969696; 49             box-shadow: 2px 2px 2px #969696; 50         } 51     </style> 52 </head> 53 <body ng-app="myApp"> 54 <form name="baseInfoForm"> 55     <div ng-controller="testCtrl"> 56         <input type="text" ng-model="age" my-valid="r"><br> 57         <input type="text" ng-model="name" my-valid="int fn:certCheck"><br> 58         <input type="button" value="http://www.mamicode.com/提交" ng-click="submit()"> 59     </div> 60 </form> 61 </body> 62 <script type="text/javascript"> 63     var app = angular.module(‘myApp‘, []); 64  65     app.controller(‘testCtrl‘, [‘$scope‘, ‘uiValidFactory‘, function ($scope, uiValidFactory) { 66                 $scope.certCheck = function (val) { 67                     if (val > 32) { 68                         return "数字太大了"; 69                     } 70                     return true; 71                 }; 72  73                 $scope.submit = function () { 74                     if (!uiValidFactory.checkValidForm($scope.baseInfoForm.$name)) { 75  76                     } 77  78                 }; 79             }] 80     ); 81  82     Math.guid = function () { 83         var a = "", b = 1; 84         for (; b <= 32; b++) { 85             var c = Math.floor(Math.random() * 16).toString(16); 86             a += c; 87             if (b === 8 || b === 12 || b === 16 || b === 20) { 88                 a += ‘-‘; 89             } 90         } 91         return a; 92     }; 93  94     String.prototype.contains = String.prototype.contains || function (a) { 95         return this.indexOf(a) != -1; 96     }; 97  98     String.prototype.format = String.prototype.format || function () { 99         var a = Array.prototype.slice.call(arguments);100         return this.replace(/\{(\d+)}/g, function (c, b) {101             return a[b];102         })103     };104 105     app.factory(‘uiTipsFactory‘, function () {106         return {107             filterClass: function (ele, invalid) {108                 if (invalid) {109                     //如果验证不通过110                     ele.removeClass(‘ng-valid‘).removeClass(‘ng-pristine‘).addClass(‘ng-invalid‘).addClass(‘ng-dirty‘);111                 } else {112                     ele.removeClass(‘ng-invalid‘).addClass(‘ng-valid‘);113                 }114             },115             on: function (ele, msg) {116                 var lastTip = ele.data(‘last-tip‘);117                 if (lastTip && lastTip === msg) {118                     return;119                 }120 121                 ele.data(‘last-tip‘, msg);122                 this.filterClass(ele, true);123 124                 var offset = ele.offset();125                 if (!offset.top && !offset.left && ele.is(‘hidden‘)) {126                     offset = ele.show().offset();127                 }128 129                 var id = ele.attr(‘ui-valid-id‘);130                 if (!id) {131                     id = Math.guid();132                     ele.attr(‘ui-valid-id‘, id);133                 }134 135                 if (id.contains(‘.‘)) {136                     id = id.replace(/\./g, ‘_‘);137                 }138 139                 var top = offset.top,140                         left = offset.left;141 142                 var getTips = function () {143                     var _tip = $(‘#vtip_‘ + id);144                     if (_tip.length) {145                         _tip.html(msg).css({146                             ‘display‘: ‘none‘,147                             ‘top‘: top + ‘px‘,148                             ‘left‘: left + ele.width() + 10 + ‘px‘149                         });150 151                     } else {152                         var html = ‘<div id="vtip_‘ + id + ‘" class="vtip qtip  qtip-rounded box-shadow-tips">‘ +153                                 ‘<div class="qtip-content">‘ + msg + ‘</div>‘;154                         $(html).css({155                             ‘display‘: ‘none‘,156                             ‘position‘: ‘absolute‘,157                             ‘top‘: top + ‘px‘,158                             ‘left‘: left + ele.width() + 10 + ‘px‘159                         }).appendTo($(‘body‘));160                     }161                 };162 163                 var bindTipsShow = function () {164                     getTips();165                     ele.unbind(‘mouseenter mouseleave‘).bind(‘mouseenter‘, function () {166                         var _tip = $(‘#vtip_‘ + id);167                         if (_tip.is(‘:hidden‘)) {168                             _tip.show();169                         }170                     }).bind(‘mouseleave‘, function () {171                         $(‘#vtip_‘ + id).hide();172                     });173 174                 };175 176                 bindTipsShow();177             },178             off: function (ele) {179                 ele.data(‘last-tip‘, ‘‘);180                 this.filterClass(ele);181                 var id = ele.attr(‘ui-valid-id‘);182 183                 if (!id) {184                     return;185                 }186 187                 if (id.contains(‘.‘)) {188                     id = id.replace(/\./g, ‘_‘);189                 }190 191                 $(‘#vtip_‘ + id).remove();192                 ele.unbind(‘mouseenter mouseleave‘);193             }194         }195     });196 197     app.factory(‘uiValidFactory‘, [‘$parse‘, ‘uiTipsFactory‘, function ($parse, tips) {198         return {199             check: function (val, rules, $scope, defaultTips, extendParam) {200                 if (!rules) {201                     return {202                         flag: true203                     };204                 }205 206                 var rulesArr = rules.split(‘ ‘),207                         isBlank = val === null || val === undefined || val === ‘‘ || (‘‘ + val === ‘‘);208 209                 //如果不是必填项 且没有输入值 则清除提示框210                 if ($.inArray(‘r‘, rulesArr) === -1 && isBlank) {211                     return {212                         flag: true213                     }214                 }215                 var i = 0, len = rulesArr.length;216                 for (; i < len; i++) {217                     var rule = rulesArr[i];218                     if (!rule) {219                         continue;220                     }221 222                     var flag = true;223                     if (‘r‘ === rule) {224                         //如果是必填项,有值 返回true225                         flag = !isBlank;226                     } else if (rule.contains(‘:‘)) {227                         //如果校验规则是 fn:ctrl.certCheck228                         flag = this.checkRule(val, rule.split(/:/), $scope, extendParam);229                     } else {230                         //校验 规则是 int 用正则匹配 数字 邮箱 长度231                         var pat = this.pats[rule];232                         if (pat instanceof RegExp) {233                             if (angular.isString(val)) {234                                 flag = this.mat(val, pat);235                             }236                         } else if (angular.isFunction(pat)) {237                             flag = pat(val);238                         } else {239                             flag = false;240                         }241                     }242 243                     //这是干什么的呢244                     if (angular.isString(flag)) {245                         return {246                             flag: false,247                             msg: flag,248                             rule: rule249                         }250                     }251 252                     if (flag === false) {253                         var msg = this.getMsg(rule, defaultTips) || this.getMsg(‘tips.valid‘);254                         console.log(msg);255                         return {256                             flag: false,257                             msg: msg,258                             rule: rule259                         }260                     }261                 }262 263                 return {264                     flag: true265                 }266             },267             checkRule: function (val, ruleArr, $scope, extendParam) {268                 //ruleArr fn:certCheck269                 var rule = ruleArr[0];270                 if (rule === ‘fn‘) {271                     fnName = ruleArr[1];//指定被调函数的名字 certCheck272                     var fn = $parse(fnName)($scope);273                     if (!fn) {274                         return true;275                     }276                     return fn.call($scope, val, extendParam);277                 } else {278                     return true;279                 }280             },281             checkValidForm: function (formName) {282                 //只检查必填项283                 //使用属性筛选器 获得里面所有的元素284                 var formContext = $(‘form[name="{0}"],[ng-form="{0}"],[data-ng-form="{0}"]‘.format(formName)),285                         validList = formContext.find(‘[my-valid]‘);//validList 不是数组,是伪数组286                 if (!validList.length) {287                     return;288                 }289 290                 var that = this,291                         validFlags = [];292                 validList.each(function () {293                             var ele = $(this),294                                     val = ele.val(),295                                     ruleStr = ele.attr(‘my-valid‘);296                             if (!ruleStr) {297                                 return true;298                             }299                             if (angular.isString(val)) {300                                 val = val.trim();301                             }302 303                             var validRules = ruleStr.split(‘ ‘);304                             if ($.inArray(‘r‘, validRules) != -1 && !val) {305                                 var modelValue = http://www.mamicode.com/ele.attr(‘ng-model‘) || ele.attr(‘data-ng-model‘);306                                 validFlags.push(modelValue);307                                 tips.on(ele, that.getMsg(‘r‘));308                             }309                         }310                 );311                 return validFlags;312             },313             mat: function (val, pat) {314                 if (!pat) {315                     return;316                 }317                 return pat.test(val);318             }319 320             ,321             getMsg: function (rule, tips) {322                 tips = tips || ‘‘;323                 //可以在界面上直接写 tips324                 if (tips && tips.contains(‘:‘)) {325                     return tips;326                 }327 328                 var msg = this.msgs[rule];329                 if (msg) {330                     var params0 = tips.contains(‘:‘) ? tips.split(/:/)[0] : ‘‘;331                     var params1 = ‘‘;332                     if (rule.startsWith(‘min‘) || rule.startsWith(‘max‘)) {333                         var ruleArr = rule.split(/:/);334                         params1 = ruleArr[ruleArr.length - 1];335                     }336                     return msg.format(params0, params1);337                 } else {338 339                 }340             }341             ,342             regPat: function (code, pat, msg) {343                 if (this.pat[code]) {344                     return;345                 }346 347                 this.pats[code] = pat;348                 this.msgs[code] = msg;349 350             }351             ,352             msgs: {353                 ‘r‘: ‘必填‘,354                 ‘int‘: ‘{0}必须为整数‘355             }356             ,357             pats: {358                 ‘int‘: /^[\-\+]?([0-9]+)$/359             }360         }361     }362     ])363     ;364 365     app.directive(‘myValid‘, [‘$parse‘, ‘uiTipsFactory‘, ‘uiValidFactory‘, function ($parse, tips, valid) {366         var uiValidAttrIdName = ‘ui-valid-id‘;367         return {368             restrict: ‘A‘,369             require: ‘ngModel‘,370             link: function (scope, el, attrs, ctrl) {371                 var validId = el.attr(uiValidAttrIdName);372 373                 if (!validId) {374                     validId = Math.guid();375                     el.attr(uiValidAttrIdName, validId);376                 }377 378                 var getRules = function () {379                     return attrs.myValid;380                 };381 382                 var lastOldRules;383 384                 var validFn = function (value, oldRules) {385                     var sp = ‘_‘;386                     var rules = getRules();387                     var r = valid.check(value, rules, scope, attrs.uiValidTips);388                     if (lastOldRules && !oldRules) {389                         oldRules = lastOldRules;390                     }391 392                     if (r.flag && oldRules) {393                         rules = rules ? rules + ‘ ‘ + oldRules : oldRules;394                     }395 396                     if (rules) {397                         var arrInner = rules.split(‘ ‘);398                         var i = 0;399                         for (; i < arrInner.length; i++) {400                             var oneRule = arrInner[i];401                             if (!oneRule.trim()) {402                                 continue;403                             }404 405                             ctrl.$setValidity(attrs.ngModel + sp + oneRule, r.flag ? true : oneRule != r.rule);406                         }407                     }408 409                     if (!r.flag) {410                         tips.on(el, r.msg);411                     } else {412                         tips.off(el);413                     }414 415                     return r.flag;416                 };417 418                 var init = function () {419                     var rules = getRules();420                     if (!rules) {421                         return;422                     }423 424                     var parsers = ctrl.$parsers;425                     if (parsers && parsers.length > 0) {426                         parsers.clean();427                     }428 429                     parsers.unshift(function (value) {430                         return validFn(value) ? value : undefined;431                     });432                 };433 434                 scope.$watch(attrs.ngModel, function (newVal, oldVal) {435                     if (newVal === oldVal) {436                         return;437                     }438                     if (ctrl.$modelValue != undefined && (ctrl.$invalid || el.hasClass(‘ng-invalid‘))) {439                         validFn(ctrl.$modelValue);440                     }441                 });442 443                 scope.$watch(getRules, function (newRules, oldRules) {444                     init();445 446                     lastOldRules = oldRules;447 448                     if (ctrl.$modelValue =http://www.mamicode.com/== undefined || ctrl.$modelValue === null) {449                         var needValid = false;450                         el.hasClass(‘ng-invalid‘);451                         var isValNaN = ctrl.$viewValue !== ctrl.$viewValue;452 453                         if (ctrl.$invalid || (ctrl.$viewValue !== undefined && !isValNaN)) {454                             needValid = true;455                         }456 457 458                         if (needValid) {459                             ctrl.$setViewValue(ctrl.$viewValue);460                         }461 462                     } else {463                         if (!ctrl.$dirty && attrs.dirtyCheck) {464                             console.log(‘----‘);465                         } else {466                             validFn(ctrl.$modelValue, oldRules);467                         }468                     }469                 });470 471 472             }473         }474     }]);475 476 </script>477 </html>
all code

 

 

angular 输入框实现自定义验证