首页 > 代码库 > 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); } } }); } } }]);
通过 监听 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]+)$/ } } } ]) ;
通过获取输入框 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‘); } } });
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]; }) };
整个代码如下:
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>
angular 输入框实现自定义验证