此插件使用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 === 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 = 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="jquery-1.11.1.js"></script> 7 <script src="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="提交" 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: true 203 }; 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: true 213 } 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 //如果是必填項,有值 返回true 225 flag = !isBlank; 226 } else if (rule.contains(':')) { 227 //如果校驗規則是 fn:ctrl.certCheck 228 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: rule 249 } 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: rule 259 } 260 } 261 } 262 263 return { 264 flag: true 265 } 266 }, 267 checkRule: function (val, ruleArr, $scope, extendParam) { 268 //ruleArr fn:certCheck 269 var rule = ruleArr[0]; 270 if (rule === 'fn') { 271 fnName = ruleArr[1];//指定被調函數的名字 certCheck 272 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 = 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 //可以在界面上直接寫 tips 324 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 === 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>
