在angularjs中的密码检查指令
我正在写密码validation指令:
Directives.directive("passwordVerify",function(){ return { require:"ngModel", link: function(scope,element,attrs,ctrl){ ctrl.$parsers.unshift(function(viewValue){ var origin = scope.$eval(attrs["passwordVerify"]); if(origin!==viewValue){ ctrl.$setValidity("passwordVerify",false); return undefined; }else{ ctrl.$setValidity("passwordVerify",true); return viewValue; } }); } }; });
html:
<input data-ng-model='user.password' type="password" name='password' placeholder='password' required> <input data-ng-model='user.password_verify' type="password" name='confirm_password' placeholder='confirm password' required data-password-verify="user.password">
给定一个表单中的2个密码字段,如果两个密码值相等,则指令影响的字段是有效的。 问题是,它的工作方式(即当我在密码validation字段中input密码)。 但是,当更新原始密码字段时,密码validation无效。
任何想法我怎么能有一个“双向绑定validation?”
这应该解决它:
视图:
<div ng-controller='Ctrl'> <form name='form'> <input data-ng-model='user.password' type="password" name='password' placeholder='password' required> <div ng-show="form.password.$error.required"> Field required</div> <input ng-model='user.password_verify' type="password" name='confirm_password' placeholder='confirm password' required data-password-verify="user.password"> <div ng-show="form.confirm_password.$error.required"> Field required!</div> <div ng-show="form.confirm_password.$error.passwordVerify"> Fields are not equal!</div> </form </div>
指示
var app = angular.module('myApp', []); app.directive("passwordVerify", function() { return { require: "ngModel", scope: { passwordVerify: '=' }, link: function(scope, element, attrs, ctrl) { scope.$watch(function() { var combined; if (scope.passwordVerify || ctrl.$viewValue) { combined = scope.passwordVerify + '_' + ctrl.$viewValue; } return combined; }, function(value) { if (value) { ctrl.$parsers.unshift(function(viewValue) { var origin = scope.passwordVerify; if (origin !== viewValue) { ctrl.$setValidity("passwordVerify", false); return undefined; } else { ctrl.$setValidity("passwordVerify", true); return viewValue; } }); } }); } }; });
我使用下面的指令,因为我想重新validation两个input字段,而不pipe值1或值2是否被更改:
指示:
'use strict'; angular.module('myApp').directive('equals', function() { return { restrict: 'A', // only activate on element attribute require: '?ngModel', // get a hold of NgModelController link: function(scope, elem, attrs, ngModel) { if(!ngModel) return; // do nothing if no ng-model // watch own value and re-validate on change scope.$watch(attrs.ngModel, function() { validate(); }); // observe the other value and re-validate on change attrs.$observe('equals', function (val) { validate(); }); var validate = function() { // values var val1 = ngModel.$viewValue; var val2 = attrs.equals; // set validity ngModel.$setValidity('equals', ! val1 || ! val2 || val1 === val2); }; } } });
用法
<input type="password" ng-model="value1" equals="{{value2}}" required> <input type="password" ng-model="value2" equals="{{value1}}" required>
为此创build一个单独的指令是不需要的。 Angular UI密码validation工具已经有了一个版本 。 有了这个你可以做到:
<input name="password" required ng-model="password"> <input name="confirm_password" ui-validate=" '$value==password' " ui-validate-watch=" 'password' "> Passwords match? {{!!form.confirm_password.$error.validator}}
还有另外一个方法就是将一个input的模型与另一个input的值相匹配。
app.directive('nxEqual', function() { return { require: 'ngModel', link: function (scope, elem, attrs, model) { if (!attrs.nxEqual) { console.error('nxEqual expects a model as an argument!'); return; } scope.$watch(attrs.nxEqual, function (value) { model.$setValidity('nxEqual', value === model.$viewValue); }); model.$parsers.push(function (value) { var isValid = value === scope.$eval(attrs.nxEqual); model.$setValidity('nxEqual', isValid); return isValid ? value : undefined; }); } }; });
因此,如果密码框的模型是login.password
那么您在validation框上设置以下属性: nx-equal="login.password"
,并testingformName.elemName.$error.nxEqual
。 像这样:
<form name="form"> <input type="password" ng-model="login.password"> <input type="password" ng-model="login.verify" nx-equal="login.password" name="verify"> <span ng-show="form.verify.$error.nxEqual">Must be equal!</span> </form>
扩大的视野:
对于我的一个新项目,我不得不修改上面的指令,以便只有当validationinput有值时才会显示nxEqual
错误。 否则, nxEqual
错误应该被静音。 这是扩展版本:
app.directive('nxEqualEx', function() { return { require: 'ngModel', link: function (scope, elem, attrs, model) { if (!attrs.nxEqualEx) { console.error('nxEqualEx expects a model as an argument!'); return; } scope.$watch(attrs.nxEqualEx, function (value) { // Only compare values if the second ctrl has a value. if (model.$viewValue !== undefined && model.$viewValue !== '') { model.$setValidity('nxEqualEx', value === model.$viewValue); } }); model.$parsers.push(function (value) { // Mute the nxEqual error if the second ctrl is empty. if (value === undefined || value === '') { model.$setValidity('nxEqualEx', true); return value; } var isValid = value === scope.$eval(attrs.nxEqualEx); model.$setValidity('nxEqualEx', isValid); return isValid ? value : undefined; }); } }; });
你会这样使用它:
<form name="form"> <input type="password" ng-model="login.password"> <input type="password" ng-model="login.verify" nx-equal-ex="login.password" name="verify"> <span ng-show="form.verify.$error.nxEqualEx">Must be equal!</span> </form>
试试看: http : //jsfiddle.net/gUSZS/
我做了没有指示。
<input type="password" ng-model="user.password" name="uPassword" required placeholder='Password' ng-minlength="3" ng-maxlength="15" title="3 to 15 characters" /> <span class="error" ng-show="form.uPassword.$dirty && form.uPassword.$error.minlength">Too short</span> <span ng-show="form.uPassword.$dirty && form.uPassword.$error.required">Password required.</span><br /> <input type="password" ng-model="user.confirmpassword" name="ucPassword" required placeholder='Confirm Password' ng-minlength="3" ng-maxlength="15" title="3 to 15 characters" /> <span class="error" ng-show="form.ucPassword.$dirty && form.ucPassword.$error.minlength">Too short</span> <span ng-show="form.ucPassword.$dirty && form.ucPassword.$error.required">Retype password.</span> <div ng-show="(form.uPassword.$dirty && form.ucPassword.$dirty) && (user.password != user.confirmpassword)"> <span>Password mismatched</span> </div>
https://github.com/wongatech/angular-confirm-field是一个很好的项目。;
这里的例子http://wongatech.github.io/angular-confirm-field/
下面的代码显示了具有实现function的2个input字段
<input ng-confirm-field ng-model="emailconfirm" confirm-against="email" name="my-email-confirm"/> <input ng-model="email" name="my-email" />
至于angular1.3.0-beta12,无效的input不写入ngModel,所以你不能看,然后validation,你可以看到在这里: http ://plnkr.co/edit/W6AFHF308nyKVMQ9vomw?p=preview。 一个新的validation器pipe道被引入,你可以附加到这个实现相同的事情。
其实,在这个笔记中,我已经创build了一个通用额外validation器的bower组件: https : //github.com/intellix/angular-validators其中包括这个。
angular.module('validators').directive('equals', function() { return { restrict: 'A', require: '?ngModel', link: function(scope, elem, attrs, ngModel) { if (!ngModel) return; attrs.$observe('equals', function() { ngModel.$validate(); }); ngModel.$validators.equals = function(value) { return value === attrs.equals; }; } }; }); angular.module('validators').directive('notEquals', function() { return { restrict: 'A', require: '?ngModel', link: function(scope, elem, attrs, ngModel) { if (!ngModel) return; attrs.$observe('notEquals', function() { ngModel.$validate(); }); ngModel.$validators.notEquals = function(value) { return value === attrs.notEquals; }; } }; });
我在成功使用这个指令之前:
.directive('sameAs', function() { return { require: 'ngModel', link: function(scope, elm, attrs, ctrl) { ctrl.$parsers.unshift(function(viewValue) { if (viewValue === scope[attrs.sameAs]) { ctrl.$setValidity('sameAs', true); return viewValue; } else { ctrl.$setValidity('sameAs', false); return undefined; } }); } }; });
用法
<input ... name="password" /> <input type="password" placeholder="Confirm Password" name="password2" ng-model="password2" ng-minlength="9" same-as='password' required>
我正在处理同样的问题,并find了一篇关于Piotr Buda写的好博客文章 。 这是一个很好的阅读,它很好地解释了这个过程。 代码如下:
directives.directive("repeatPassword", function() { return { require: "ngModel", link: function(scope, elem, attrs, ctrl) { var otherInput = elem.inheritedData("$formController")[attrs.repeatPassword]; ctrl.$parsers.push(function(value) { if(value === otherInput.$viewValue) { ctrl.$setValidity("repeat", true); return value; } ctrl.$setValidity("repeat", false); }); otherInput.$parsers.push(function(value) { ctrl.$setValidity("repeat", value === ctrl.$viewValue); return value; }); } }; });
所以你可以做这样的事情:
<input type="password" name="repeatPassword" id="repeatPassword" placeholder="repeat password" ng-model="user.repeatPassword" repeat-password="password" required>
信贷交给作者
这不够好:
<input type="password" ng-model="passwd1" /> <input type="password" ng-model="passwd2" /> <label ng-show="passwd1 != passwd2">Passwords do not match...</label> <button ng-disabled="passwd1 != passwd2">Save</button>
简单,对我来说工作得很好。
这个解决scheme类似于Dominic Watson给出的解决scheme,它使用$ validators并且是我最喜欢的一个。 唯一的变化就是你可以看一个表情。
$ validators每当模型值更改时应用的validation程序集合。 对象中的键值是指validation器的名称,而函数是指validation操作。 validation操作以模型值作为参数提供,并且必须根据validation的响应返回true或false值
从https://code.angularjs.org/1.3.15/docs/api/ng/type/ngModel.NgModelController
我正在使用angular1.3。 我的指令看起来像这样
angular.module('app').directive("passwordConfirm", function() { "use strict"; return { require : "ngModel", restrict : "A", scope : { //We will be checking that our input is equals to this expression passwordConfirm : '&' }, link : function(scope, element, attrs, ctrl) { //The actual validation function passwordConfirmValidator(modelValue, viewValue) { return modelValue == scope.passwordConfirm(); } //Register the validaton when this input changes ctrl.$validators.passwordConfirm = passwordConfirmValidator; //Also validate when the expression changes scope.$watch(scope.passwordConfirm, ctrl.$validate); } }; });
使用它
<input type="password" ng-model="user.password"/> <input type="password" ng-model="user.confirmPassword" password-confirm="user.password" />
为了validation两个input字段的forms,我find了最合适的方法
指示
app.directive('passwordVerify', function() { return { require: 'ngModel', link: function (scope, elem, attrs, ctrl) { if (!attrs.passwordVerify) { return; } scope.$watch(attrs.passwordVerify, function (value) { if( value === ctrl.$viewValue && value !== undefined) { ctrl.$setValidity('passwordVerify', true); ctrl.$setValidity("parse",undefined); } else { ctrl.$setValidity('passwordVerify', false); } }); ctrl.$parsers.push(function (value) { var isValid = value === scope.$eval(attrs.passwordVerify); ctrl.$setValidity('passwordVerify', isValid); return isValid ? value : undefined; }); } }; });
HTML
<div class="row"> <div class="col-md-10 col-md-offset-1"> <div class="form-group" ng-class="{ 'has-error': form.password.$dirty && form.password.$error.required || (form.password.$error.minlength || form.password.$error.maxlength)}"> <input type="password" name="password" ng-minlength="6" ng-maxlength="16" id="password" class="form-control" placeholder="Password" ng-model="user.password" required /> <span ng-show="form.password.$dirty && form.password.$error.required" class="help-block">Password is required</span> <span ng-show="form.password.$error.minlength || form.password.$error.maxlength" class="help-block">Password must be 6-16 character long</span> </div> </div> </div> <div class="row"> <div class="col-md-10 col-md-offset-1"> <div class="form-group" ng-class="{ 'has-error': (form.confirm_password.$dirty && form.confirm_password.$error.required) || form.confirm_password.$error.passwordVerify }"> <input type="password" name="confirm_password" id="confirm_password" class="form-control" placeholder="Confirm Password" ng-model="user.confirm_password" required password-verify="user.password" /> <span ng-show="form.confirm_password.$dirty && form.confirm_password.$error.required" class="help-block">Confirm Password is required</span> <span ng-show="form.confirm_password.$error.passwordVerify" class="help-block">Please make sure passwords match & must be 6-16 character long</span> </div> </div> </div>
这既有效,又简单,干净
JavaScript的
var app = angular.module("app"); app.controller("SamePaswordController", function () { this.password; this.confirm; this.save = function () { alert("Saved!"); }; } app.directive("match", function () { return { restrict:"A", require:"ngModel", link: function(scope, element, attrs, ctrl) { function matchValidator(value) { scope.$watch(attrs.match, function(newValue, oldValue) { var isValid = value === scope.$eval(attrs.match); ctrl.$setValidity('match', isValid); }); return value; } ctrl.$parsers.push(matchValidator); } }; });
HTML:注意匹配指令
<form name="regForm" ng-controller="SamePaswordController as regCtrl" ng-submit="regForm.$valid && regCtrl.save()" novalidate> <input name="password" ng-model="regCtrl.password" type="password" required placeholder="Password"/> <input name="confirm" ng-model="regCtrl.confirm" match="regCtrl.password" type="password" required placeholder="Confirm password"/> <div> regForm is valid:{{regForm.$valid}}</div> <input type="submit" value="Save"/> </form>
不是一个指令性的解决scheme,但为我工作:
<input ng-model='user.password' type="password" name='password' placeholder='password' required> <input ng-model='user.password_verify' type="password" name='confirm_password' placeholder='confirm password' ng-pattern="getPattern()" required>
而在控制器中:
//Escape the special chars $scope.getPattern = function(){ return $scope.user.password && $scope.user.password.replace(/([.*+?^${}()|\[\]\/\\])/g, '\\$1'); }
以下是我对这个问题的看法。 这个指令将比较一个表单值而不是范围。
'use strict'; (function () { angular.module('....').directive('equals', function ($timeout) { return { restrict: 'A', require: ['^form', 'ngModel'], scope: false, link: function ($scope, elem, attrs, controllers) { var validationKey = 'equals'; var form = controllers[0]; var ngModel = controllers[1]; if (!ngModel) { return; } //run after view has rendered $timeout(function(){ $scope.$watch(attrs.ngModel, validate); $scope.$watch(form[attrs.equals], validate); }, 0); var validate = function () { var value1 = ngModel.$viewValue; var value2 = form[attrs.equals].$viewValue; var validity = !value1 || !value2 || value1 === value2; ngModel.$setValidity(validationKey, validity); form[attrs.equals].$setValidity(validationKey,validity); }; } }; }); })();
在HTML中,现在指的是实际的forms,而不是范围值:
<form name="myForm"> <input type="text" name="value1" equals="value2"> <input type="text" name="value2" equals="value1"> <div ng-show="myForm.$invalid">The form is invalid!</div> </form>
为了在两个input都改变的情况下实现validation,我使用下面的代码(这是所有其他答案的组合):
angular.module('app.directives') .directive('passwordVerify', [function () { return { require: '?ngModel', restrict: 'A', scope: { origin: '=passwordVerify' }, link: function (scope, element, attrs, ctrl) { if(!ctrl) { return; } function validate(value) { ctrl.$setValidity('passwordMatch', scope.origin === value); return value; } ctrl.$parsers.unshift(validate); scope.$watch('origin', function(value) { validate(ctrl.$viewValue); }); } }; }]);
首先,我要感谢Fredric发表这个出色的例子。 偶然碰巧遇到一个小问题。 在小提琴你张贴http://jsfiddle.net/gUSZS/
如果你input密码,然后在validationinput元素中input相同的密码,一切正常,但尝试添加一个空间到第二个盒子,angular将自动修剪该空间。 这意味着该指令不会“看到”额外的空间。 现在密码是不同的,但表格仍然有效。
要解决这个问题,我们需要添加
ng-trim="false"
到input元素。 这不适用于angular度1.0.3,所以如果你想在这个小提琴中尝试它,你需要添加1.1.1小提琴( http://ajax.googleapis.com/ajax/libs/angularjs/1.1.1/angular .js )
但是,再次,比弗雷德里克,我会在我的应用程序中使用你的解决scheme!
安东PS我想评论弗雷德里克的post,但林新来这个论坛,似乎没有足够的信誉。 所以,如果你喜欢它,如果你们中的一些人可以投票给我的评论,将非常感激:-)
不需要额外的指令,这是我的承担:
HTML:
<div class="form-group" data-ng-class="{ 'has-error': submitted && !form.new_passwd.$valid }"> <input type="password" name="new_passwd" class="form-control" data-ng-model="data.new_passwd" placeholder="New Password" required data-ng-pattern="passwdRegex"> <small class="help-block" data-ng-show="submitted && form.new_passwd.$error.required">New password is required!</small> <small class="help-block" data-ng-show="submitted && !form.new_passwd.$error.required && form.new_passwd.$error.pattern">New password is not strong enough!</small> </div> <div class="form-group" data-ng-class="{ 'has-error': submitted && !form.new_passwd_conf.$valid }"> <input type="password" name="new_passwd_conf" class="form-control" data-ng-model="data.new_passwd_conf" placeholder="Confirm New Password" required data-ng-pattern="passwdConfRegex"> <small class="help-block" data-ng-show="submitted && form.new_passwd_conf.$error.required">New password confirmation is required!</small> <small class="help-block" data-ng-show="submitted && !form.new_passwd_conf.$error.required && form.new_passwd_conf.$error.pattern">New password confirmation does not match!</small> </div>
使用Javascript:
$scope.passwdRegex = /^(?=.*[AZ])(?=.*[az])(?=.*\d)(?=.*[^\da-zA-Z]).{8,}$/; $scope.$watch('data.new_passwd', function() { $scope.passwdConfRegex = new RegExp(Regex.escape($scope.data.new_passwd)); });
Regex.escape()可以在这里find。
奇迹般有效!
为了增加大量现有的解决scheme,这对我来说很好。
( Jan Laussmann的回答停止与最新的AngularJStesting版发布)。
指示:
angular.module('myApp').directive('matchValidator', [function() { return { require: 'ngModel', link: function(scope, elm, attr, ctrl) { var pwdWidget = elm.inheritedData('$formController')[attr.matchValidator]; ctrl.$parsers.push(function(value) { if (value === pwdWidget.$viewValue) { ctrl.$setValidity('match', true); return value; } if (value && pwdWidget.$viewValue) { ctrl.$setValidity('match', false); } }); pwdWidget.$parsers.push(function(value) { if (value && ctrl.$viewValue) { ctrl.$setValidity('match', value === ctrl.$viewValue); } return value; }); } }; }])
用法
<input type="email" ng-model="value1" name="email" required> <input type="email" ng-model="value2" name="emailConfirm" match-validator="email" required>
显示错误
<div ng-if="[[yourFormName]].emailConfirm.$error"> <div ng-if="[[yourFormName]].emailConfirm.$error.match"> Email addresses don't match. </div> </div>
<input name="password" type="text" required="" ng-model="password" placeholder="password" class="ng-dirty ng-valid ng-valid-required"> <input name="confirm_password" type="text" required="" ng-model="confirm_password" ui-validate=" '$value==password' " ui-validate-watch=" 'password' " placeholder="confirm password" class="ng-dirty ng-valid-required ng-invalid ng-invalid-validator"> <span ng-show="form.confirm_password.$error.validator">Passwords do not match!</span> password errors: { "required": false, "validator": true }
这对我有效。
指示:
modulename.directive('passwordCheck', function () { return { restrict: 'A', // only activate on element attribute require: '?ngModel', // get a hold of NgModelController link: function (scope, elem, attrs, ngModel) { if (!ngModel) return; // do nothing if no ng-model var Value = null; // watch own value and re-validate on change scope.$watch(attrs.ngModel, function (val) { Value = val; validate(); }); // observe the other value and re-validate on change attrs.$observe('passwordCheck', function () { validate(); }); var validate = function () { // values var val1 = Value; var val2 = attrs.passwordCheck; // set validity if (val1 != '' && val1 != undefined) { ngModel.$setValidity('passwordCheck', val1 == val2); } else { ngModel.$setValidity('passwordCheck', true); } }; } } });
HTML:
ng-model="confirmpassword.selected" type="password" name="confirmpassword" password-check="{{password.selected}}" ng-show="resetpasswordform.confirmpassword.$error.passwordCheck && submitted" Password does not match
当我尝试构build自己的指令时遇到了同样的问题,并使用此添加进行了修复
ctrl.$validate();
其中ctrl是我的ngModelController
这是我的看法
<input type="password" match="signupCtrl.registrationData.password" name="confirmPassword" class="form-control" placeholder="Confirm Password" data-ng-model="signupCtrl.registrationData.confirmPassword" required> <span ng-messages="registerForm.confirmPassword.$error"> <span ng-message="match">The Password must match</span> </span>
这是我的指示
(function () { 'use strict'; angular.module('matchDirective', [ // Angular modules // Custom modules // 3rd Party Modules ]); })(); (function () { 'use strict'; angular .module('matchDirective') .directive('match', match); match.$inject = ['$window']; function match($window) { // Usage: // <element match="source"></element> // Creates: // var directive = { link: link, restrict: 'A', require: 'ngModel', }; return directive; function link(scope, element, attrs, ctrl) { scope.$watch(attrs['match'], function (newVal, oldVal) { ctrl.$validators.match = function (modelValue, viewValue) { if (newVal == modelValue) { return true; } else { return false; } } ctrl.$validate(); }); } } })();
像这样的东西适合我:
JS:
.directive('sameAs', function() { return { require : 'ngModel', link : function(scope, elm, attrs, ngModelCtrl) { ngModelCtrl.$validators.sameAs = function(modelValue, viewValue) { var checkedVal = attrs.sameAs; var thisInputVal = viewValue; if (thisInputVal == checkedVal) { return true; // valid } else { return false; } }; } }; });
HTML:
<input type="password" name="password" id="password" ng-model="password" /> <input type="password" name="passwordRepeat" id="passwordRepeat" ng-model="passwordRepeat" same-as="{{password}}" />
保持简单和愚蠢(KISS)的原则可能是有用的这一个。 通过执行以下操作,更快更容易地检查两个密码是否匹配:
<div ng-app="app" ng-controller="passwordCheck"> <form name="signUp" ng-submit="submitForm()" novalidate> <input type="password" name="password" ng-model="password" required> <input type="password" name="ConfirmPassword" ng-model="passwordconfirm" required> <button type="submit"> Submit</button> </form> <hr> <span>Do they match?</span> {{signUp.password.$viewValue == signUp.confirmPassword.$viewValue}} </div>
在提交表单之前,你可以在你的js中做到这一点
var app = angular.module("app", []); app.controller("passwordCheck", function($scope) { $scope.submitForm = function() { if ($scope.signUp.$valid && $scope.signUp.password.$viewValue == $scope.signUp.confirmPassword.$viewValue) { alert('Its a match!'); }; }; });
你也可以在JSfiddle中testing它。