Angular 输入框实现自定义验证功能

发布时间 - 2026-01-10 23:09:04    点击率:

此插件使用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];
  })
 };

   整个代码如下:

<!DOCTYPE html>
<html>
<head lang="en">
 <meta charset="UTF-8">
 <title></title>
 <script src="jquery-1.11.1.js"></script>
 <script src="angular.js"></script>
 <style type="text/css">
  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;
  }
 </style>
</head>
<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>
<script type="text/javascript">
 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];
  })
 };
 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');
   }
  }
 });
 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]+)$/
   }
  }
 }
 ])
 ;
 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);
      }
     }
    });
   }
  }
 }]);
</script>
</html>


# angular  # 输入框验证  # angular自定义验证  # AngularJS实现表单验证  # 详解Angular开发中的登陆与身份验证  # AngularJS使用ngMessages进行表单验证  # AngularJS实现表单手动验证和表单自动验证  # Angular2表单自定义验证器的实现  # angular实现表单验证及提交功能  # AngularJs验证重复密码的方法(两种)  # Ionic+AngularJS实现登录和注册带验证功能  # AngularJS身份验证的方法  # AngularJS手动表单验证  # Angular简单验证功能示例  # 必填  # 输入框  # 不通过  # 这是  # 浮点  # 如果不是  # 太大了  # 鼠标  # 则是  # 自定义  # 重写  # 用户可以  # 来实现  # 背景色  # 判断是否  # 正则表达式  # valid  # submit  # click  # button 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: Python图片处理进阶教程_Pillow滤镜与图像增强  如何用wdcp快速搭建高效网站?  Python进程池调度策略_任务分发说明【指导】  HTML 中如何正确使用模板变量为元素的 name 属性赋值  JavaScript中如何操作剪贴板_ClipboardAPI怎么用  实例解析Array和String方法  php后缀怎么变mp4格式错误_修改扩展名提示格式不对怎么办【技巧】  如何在阿里云通过域名搭建网站?  Laravel请求验证怎么写_Laravel Validator自定义表单验证规则教程  网站建设保证美观性,需要考虑的几点问题!  网站制作怎么样才能赚钱,用自己的电脑做服务器架设网站有什么利弊,能赚钱吗?  如何在云服务器上快速搭建个人网站?  什么是JavaScript解构赋值_解构赋值有哪些实用技巧  如何用手机制作网站和网页,手机移动端的网站能制作成中英双语的吗?  Laravel如何使用Socialite实现第三方登录?(微信/GitHub示例)  香港服务器网站生成指南:免费资源整合与高速稳定配置方案  微信小程序 require机制详解及实例代码  高防服务器租用首荐平台,企业级优惠套餐快速部署  高端云建站费用究竟需要多少预算?  Laravel如何发送系统通知_Laravel Notifications实现多渠道消息通知  如何彻底删除建站之星生成的Banner?  谷歌Google入口永久地址_Google搜索引擎官网首页永久入口  如何获取免费开源的自助建站系统源码?  JavaScript如何实现倒计时_时间函数如何精确控制  jQuery中的100个技巧汇总  Laravel如何处理和验证JSON类型的数据库字段  Laravel如何创建自定义Artisan命令?(代码示例)  Laravel如何实现一对一模型关联?(Eloquent示例)  Laravel如何实现多表关联模型定义_Laravel多对多关系及中间表数据存取【方法】  Windows11怎样设置电源计划_Windows11电源计划调整攻略【指南】  Win11摄像头无法使用怎么办_Win11相机隐私权限开启教程【详解】  Laravel怎么返回JSON格式数据_Laravel API资源Response响应格式化【技巧】  绝密ChatGPT指令:手把手教你生成HR无法拒绝的求职信  为什么要用作用域操作符_php中访问类常量与静态属性的优势【解答】  高端建站如何打造兼具美学与转化的品牌官网?  如何在腾讯云服务器快速搭建个人网站?  如何在阿里云高效完成企业建站全流程?  如何用ChatGPT准备面试 模拟面试问答与职场话术练习教程  Bootstrap整体框架之CSS12栅格系统  英语简历制作免费网站推荐,如何将简历翻译成英文?  python中快速进行多个字符替换的方法小结  php增删改查怎么学_零基础入门php数据库操作必知基础【教程】  如何快速搭建高效香港服务器网站?  Laravel如何实现数据库事务?(DB Facade示例)  如何在阿里云虚拟机上搭建网站?步骤解析与避坑指南  网站制作免费,什么网站能看正片电影?  Laravel怎么实现搜索高亮功能_Laravel结合Scout与Algolia全文检索【实战】  如何在阿里云购买域名并搭建网站?  中山网站推广排名,中山信息港登录入口?  如何用PHP工具快速搭建高效网站?