用AngularJS比较表单validation中的两个input值
我正在尝试使用AngularJS进行表单validation。 我特别感兴趣的是比较两个值。 我希望用户在继续之前确认他input的一些数据。 可以说我有下面的代码:
<p> Email:<input type="email" name="email1" ng-model="emailReg"> Repeat Email:<input type="email" name="email2" ng-model="emailReg2"> <p>
然后我可以使用validation:
<span ng-show="registerForm.email1.$error.required">Required!</span> <span ng-show="registerForm.email1.$error.email">Not valid email!</span> <span ng-show="emailReg !== emailReg2">Emails have to match!</span> <-- see this line
registerForm。$ valid将对input中的文本作出正确的反应,除非我不知道如何在此validation中使用比较来强制电子邮件在允许用户提交表单之前是相同的。
我很想拥有一个没有自定义指令的解决scheme,但是如果没有这个方法就无法实现,我会处理它。 这是一个解决类似问题的自定义指令的答案。
任何帮助表示感谢,谢谢
一种方法是使用自定义指令。 这里是一个使用ngMatch指令的例子:
<p>Email:<input type="email" name="email1" ng-model="emailReg"> Repeat Email:<input type="email" name="email2" ng-model="emailReg2" ng-match="emailReg"></p> <span data-ng-show="myForm.emailReg2.$error.match">Emails have to match!</span>
注意:一般不build议使用ng-
作为自定义指令的前缀,因为它可能与官方的AngularJS指令冲突。
更新
也可以在不使用自定义指令的情况下获得此function:
HTML
<button ng-click="add()></button> <span ng-show="IsMatch">Emails have to match!</span>
调节器
$scope.add = function() { if ($scope.emailReg != $scope.emailReg2) { $scope.IsMatch=true; return false; } $scope.IsMatch=false; }
你应该能够使用ng-pattern / regex来比较2个input值
Email:<input type="email" name="email1" ng-model="emailReg"> Repeat Email:<input type="email" name="email2" ng-model="emailReg2" ng-pattern="emailReg">
并用以下方式validation
<span ng-show="registerForm.email2.$error.pattern">Repeat Email should have the same value with email!</span>
trainosais – 你是对的,validation应该在指令级完成。 它干净,模块化,并允许代码的可重用性。 当你在控制器中进行基本的validation时,你可以一遍又一遍地写出不同的表单。 这是超级防干的。
最近我有一个类似的问题,并用一个简单的指令对它进行了sorting,插入到parsing器pipe道中,因此与Angular架构保持一致。 链接validation器使其非常容易重用,在我看来这应该被认为是唯一的解决scheme。
简而言之,这里是简化的标记:
<form novalidate="novalidate"> <label>email</label> <input type="text" ng-model="email" name="email" /> <label>email repeated</label> <input ng-model="emailRepeated" same-as="email" name="emailRepeated" /> </form>
和JS代码:
angular.module('app', []) .directive('sameAs', function() { return { require: 'ngModel', link: function(scope, elem, attrs, ngModel) { ngModel.$parsers.unshift(validate); // Force-trigger the parsing pipeline. scope.$watch(attrs.sameAs, function() { ngModel.$setViewValue(ngModel.$viewValue); }); function validate(value) { var isValid = scope.$eval(attrs.sameAs) == value; ngModel.$setValidity('same-as', isValid); return isValid ? value : undefined; } } }; });
该指令挂钩到parsing器stream水线中,以获得对视图值的任何改变的通知,并且基于新的视图值和参考字段的值的比较来设置有效性。 这一点很容易。 棘手的一点是嗅探参考字段的变化。 为此,该指令在引用值上设置一个观察器,并强制parsingstream水线,以使所有validation器再次运行。
如果你想玩它,这是我的笔: http : //codepen.io/jciolek/pen/kaKEn
Jacek,我希望这会有所帮助
我最近写了一个自定义的指令,可以足够通用的做任何validation。 它从当前作用域取一个validation函数
module.directive('customValidator', [function () { return { restrict: 'A', require: 'ngModel', scope: { validateFunction: '&' }, link: function (scope, elm, attr, ngModelCtrl) { ngModelCtrl.$parsers.push(function (value) { var result = scope.validateFunction({ 'value': value }); if (result || result === false) { if (result.then) { result.then(function (data) { //For promise type result object ngModelCtrl.$setValidity(attr.customValidator, data); }, function (error) { ngModelCtrl.$setValidity(attr.customValidator, false); }); } else { ngModelCtrl.$setValidity(attr.customValidator, result); return result ? value : undefined; //For boolean result return based on boolean value } } return value; }); } }; }]);
要使用它,你做
<input type="email" name="email2" ng-model="emailReg2" custom-validator='emailMatch' data-validate-function='checkEmailMatch(value)'> <span ng-show="registerForm.email2.$error.emailMatch">Emails have to match!</span>
在你的控制器,那么你可以实现的方法,应该返回true或false
$scope.checkEmailMatch=function(value) { return value===$scope.emailReg; }
好处是,您不必为每个自定义validation编写自定义指令。
当angular度升级到1.3以上时,我发现使用Jacek Ciolek的很好的答案是一个问题:
- 将数据添加到参考字段
- 将相同的数据添加到指令上的字段(该字段现在是有效的)
- 返回参考字段并更改数据(指令字段保持有效)
我testing了rdukeshier的答案 (将var modelToMatch = element.attr('sameAs')
为var modelToMatch = attrs.sameAs
以正确检索参考模型),但发生了同样的问题。
为了解决这个问题(在angular1.3和1.4中testing),我修改了rdukeshier的代码,并在参考字段上添加了一个观察器,以便在参考字段更改时运行所有validation。 该指令现在看起来像这样:
angular.module('app', []) .directive('sameAs', function () { return { require: 'ngModel', link: function(scope, element, attrs, ctrl) { var modelToMatch = attrs.sameAs; scope.$watch(attrs.sameAs, function() { ctrl.$validate(); }) ctrl.$validators.match = function(modelValue, viewValue) { return viewValue === scope.$eval(modelToMatch); }; } }; });
更新codepen
使用ng-pattern,这样ng-valid和ng-dirty就可以正常工作
Email:<input type="email" name="email1" ng-model="emailReg"> Repeat Email:<input type="email" name="email2" ng-model="emailReg2" ng-pattern="emailReg"> <span ng-show="registerForm.email2.$error.pattern">Emails have to match!</span>
不需要function或指令。 只需从视图中比较他们的$ modelValue:
ng-show="formName.email.$modelValue !== formName.confirmEmail.$modelValue"
更详细的例子:
<span ng-show="(formName.email.$modelValue !== formName.confirmEmail.$modelValue) && formName.confirmEmail.$touched && !formName.confirmEmail.$error.required">Email does not match.</span>
请注意 ,ConfirmEmail不在ViewModel中; 它是$ scope的属性。 它不需要提交。
@ Henry-Neo的方法很接近,它只是需要更严格的正则expression式规则。
<form name="emailForm"> Email: <input type="email" name="email1" ng-model="emailReg"> Repeat Email: <input type="email" name="email2" ng-model="emailReg2" ng-pattern="(emailReg)"> </form>
通过在括号内包含正则expression式规则,它将匹配emailReg
的整个string到emailReg2
并且会导致表单validation失败,因为它不匹配。
然后,您可以钻取元素以找出哪个部分失败。
<p ng-show="emailForm.$valid">Form Valid</p> <p ng-show="emailForm.email1.$error">Email not valid</p> <p ng-show="emailForm.email1.$valid && emailForm.email1.$error.pattern"> Emails Do Not Match </p>
感谢这个伟大的例子@Jacek Ciolek 。 对于angular1.3.x,当更新参考input值时,此解决scheme会中断。 基于这个angular1.3.x的例子,这个解决scheme与Angular 1.3.x一样。 它绑定并监视参考值的变化。
angular.module('app', []).directive('sameAs', function() { return { restrict: 'A', require: 'ngModel', scope: { sameAs: '=' }, link: function(scope, elm, attr, ngModel) { if (!ngModel) return; attr.$observe('ngModel', function(value) { // observes changes to this ngModel ngModel.$validate(); }); scope.$watch('sameAs', function(sameAs) { // watches for changes from sameAs binding ngModel.$validate(); }); ngModel.$validators.sameAs = function(value) { return scope.sameAs == value; }; } }; });
这是我的笔: http : //codepen.io/kvangrae/pen/BjxMWR
该模块适用于比较两个字段。 适用于Angular 1.3+。 简单易用https://www.npmjs.com/package/angular-password
它也允许将模块保存为通用模块。 只要将它们包含在你的模块的包列表中。
这里是sameAs指令的angular度1.3版本:
angular.module('app').directive('sameAs', [function() { 'use strict'; return { require: 'ngModel', restrict: 'A', link: function(scope, element, attrs, ctrl) { var modelToMatch = element.attr('sameAs'); ctrl.$validators.match = function(modelValue, viewValue) { return viewValue === scope.$eval(modelToMatch); }; } }; }]);
我的解决scheme类似于我的解决scheme。 唯一的区别是我的模型。 我在我的htmlinput中有以下模型:
ng-model="new.Participant.email" ng-model="new.Participant.confirmEmail"
在我的控制器中,我有这个在$范围内:
$scope.new = { Participant: {} };
这个validation线路工作:
<label class="help-block" ng-show="new.Participant.email !== new.Participant.confirmEmail">Emails must match! </label>
你必须看到更大的问题。 如何编写解决一个问题的指令。 你应该尝试指令use-form-error 。 这有助于解决这个问题,还有其他许多问题。
<form name="ExampleForm"> <label>Password</label> <input ng-model="password" required /> <br> <label>Confirm password</label> <input ng-model="confirmPassword" required /> <div use-form-error="isSame" use-error-expression="password && confirmPassword && password!=confirmPassword" ng-show="ExampleForm.$error.isSame">Passwords Do Not Match!</div> </form>
现场示例jsfiddle
我需要在我的整个应用程序中以一种forms做到这一点,我看到一个像我的情况超级复杂的指令,所以我使用ng-patter
像一些有点,但有一些问题,当string有特殊字符.[\
打破了,所以我创build了一个花样特殊字符的函数。
$scope.escapeRegExp(str) { return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); }
并在视图中
<form name="ExampleForm"> <label>Password</label> <input ng-model="password" required /> <br> <label>Confirm password</label> <input ng-model="confirmPassword" required ng-pattern="escapeRegExp(password)"/> </form>
这是我自定义validation器指令的简单版本:
angular.module('app') .directive('equalsTo', function () { return { require: 'ngModel', link: function (scope, elm, attrs, ngModel) { scope.$watchGroup([attrs.equalsTo, () => ngModel.$modelValue], newVal => { ngModel.$setValidity('equalsTo', newVal[0] === newVal[1]); }); } }; })
当然,对于非常简单的比较,你总是可以使用ngMin
/ ngMax
。
否则,你可以使用自定义指令,并且不需要做任何$watch
或者$observe
或者$eval
或者这个花哨的$setValidity
来回。 另外,根本不需要挂接postLinkfunction。 尽量避免使用DOM,因为这是违背angular度的。
只需使用生命周期挂钩框架给你。 每次更改都添加一个validation器和$validate
。 就那么简单。
app.directive('sameAs', function() { return { restrict: 'A', require: { ngModelCtrl: 'ngModel' }, scope: { reference: '<sameAs' }, bindToController: true, controller: function($scope) { var $ctrl = $scope.$ctrl; //add the validator to the ngModelController $ctrl.$onInit = function() { function sameAsReference (modelValue, viewValue) { if (!$ctrl.reference || !modelValue) { //nothing to compare return true; } return modelValue === $ctrl.reference; } $ctrl.ngModelCtrl.$validators.sameas = sameAsReference; }; //do the check at each change $ctrl.$onChanges = function(changesObj) { $ctrl.ngModelCtrl.$validate(); }; }, controllerAs: '$ctrl' }; });
你的闯入者