diretiva de verificação de senha em angularjs

Eu estou escrevendo uma diretiva de verificação de senha:

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:

   

Dados dois campos de senha em um formulário, se os dois valores de senha forem iguais, o campo afetado pela diretiva será válido. A questão é que funciona de uma maneira (ou seja, quando eu digito uma senha no campo de verificação de senha). No entanto, quando o campo de senha original é atualizado, a verificação da senha não se torna válida.

Alguma idéia de como eu poderia ter um “two-way binding verify?”

Isso deve resolvê-lo:

Visão:

 
Field required
Field required!
Fields are not equal!

Directiva

 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; } }); } }); } }; }); 

Eu uso a seguinte diretiva porque quero validar novamente o campo de input, independentemente de o valor 1 ou o valor 2 ter sido alterado:

directiva:

 '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); }; } } }); 

uso

   

Criar uma diretiva separada para isso não é necessário. Já existe um build na ferramenta de validação de senhas do Angular UI . Com isso você poderia fazer:

   Passwords match? {{!!form.confirm_password.$error.validator}} 

Ainda outra abordagem é corresponder o modelo de uma input ao valor de outra 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; }); } }; }); 

Portanto, se o modelo da checkbox de senha for login.password , você definirá o seguinte atributo na checkbox de verificação: nx-equal="login.password" e test para formName.elemName.$error.nxEqual . Igual a:

 
Must be equal!

Versão extendida:

Para um novo projeto meu, tive que modificar a diretiva acima para que ela exibisse apenas o erro nxEqual quando, e somente quando, a input de verificação tivesse um valor. Caso contrário, o erro nxEqual deve ser silenciado. Aqui está a versão estendida:

 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; }); } }; }); 

E você usaria assim:

 
Must be equal!

Experimente: http://jsfiddle.net/gUSZS/

Eu fiz isso sem diretiva.

  Too short Password required.
Too short Retype password.
Password mismatched

https://github.com/wongatech/angular-confirm-field é um bom projeto para isso.

Exemplo aqui http://wongatech.github.io/angular-confirm-field/

O código abaixo mostra 2 campos de input com a funcionalidade implementada

   

A partir de 1.3.0-beta12 angular, inputs inválidas não são gravadas no ngModel, portanto, você não pode assistir AND THEN validate, como pode ver aqui: http://plnkr.co/edit/W6AFHF308nyKVMQ9vomw?p=preview . Um novo pipeline de validadores foi introduzido e você pode append isso para obter a mesma coisa.

Na verdade, nessa nota, criei um componente bower para validadores extras comuns: https://github.com/intellix/angular-validators, que inclui isso.

 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; }; } }; }); 

Eu usei esta diretiva com sucesso antes:

  .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; } }); } }; }); 

Uso

    

Eu estava lidando com o mesmo problema e encontrei um bom post sobre isso escrito por Piotr Buda. É uma boa leitura e explica muito bem o processo. O código é o seguinte:

 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; }); } }; }); 

Então você poderia fazer algo como:

  

O crédito vai para o autor

Isso não é bom o suficiente:

     

Simples, e funciona muito bem para mim.

Essa solução é semelhante à dada por Dominic Watson, que usa $ validators e é a que eu mais gosto. As únicas mudanças são que você pode assistir a uma expressão.

$ validators Uma coleção de validadores que são aplicados sempre que o valor do modelo é alterado. O valor da chave dentro do object refere-se ao nome do validador enquanto a function se refere à operação de validação. A operação de validação é fornecida com o valor do modelo como um argumento e deve retornar um valor verdadeiro ou falso, dependendo da resposta dessa validação

de https://code.angularjs.org/1.3.15/docs/api/ng/type/ngModel.NgModelController

Eu estou usando 1.3 angular. Minha diretiva é algo parecido com isto

 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); } }; }); 

Para usá-lo

   

Para validar a forma com dois campos de input, eu acho o modo mais adequado de

Directiva

 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

  
Password is required Password must be 6-16 character long
Confirm Password is required Please make sure passwords match & must be 6-16 character long

Isso funciona nos dois sentidos e é simples e limpo

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: observe a diretiva de correspondência

 
regForm is valid:{{regForm.$valid}}

Você pode clonar o repository com este exemplo https://github.com/rogithub/roangularjs

Não é uma solução diretiva, mas está funcionando para mim:

   

E no controlador:

 //Escape the special chars $scope.getPattern = function(){ return $scope.user.password && $scope.user.password.replace(/([.*+?^${}()|\[\]\/\\])/g, '\\$1'); } 

http://plnkr.co/edit/QDTnipCsHdg56vgygsqC?p=preview

A seguir, minha opinião sobre o problema. Essa diretiva seria comparada com um valor de formulário em vez do escopo.

 '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); }; } }; }); })(); 

no HTML agora se refere ao formulário real em vez do valor do escopo:

 
The form is invalid!

Para obter validação quando as duas inputs mudam, eu uso o seguinte código (que foi uma combinação de todas as outras outras respostas):

 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); }); } }; }]); 

Primeiramente, gostaria de agradecer a Fredric por postar este excelente exemplo. Há um pequeno problema que eu encontrei por coincidência. no violino você postou http://jsfiddle.net/gUSZS/

Se você digitar uma senha e, em seguida, digitar a mesma senha no elemento de input de verificação, tudo funcionará bem, mas tente adicionar um espaço à segunda checkbox e o ângulo reduzirá automaticamente esse espaço. Isso significa que a diretiva não “vê” o espaço extra. Agora as senhas são diferentes, mas a forma ainda é válida.

para corrigir isso, precisamos adicionar

 ng-trim="false" 

aos elementos de input. Isso não funciona em 1.0.3 angular então se você quiser experimentá-lo neste violino você precisa adicionar 1.1.1 ao violino ( http://ajax.googleapis.com/ajax/libs/angularjs/1.1.1/angular .js )

Mas, novamente, obrigado Frederic, vou usar sua solução no meu aplicativo!

Anton PS Eu queria comentar o post de Frederic, mas sou novo neste fórum e não tenho crédito suficiente. Por isso, seria muito apreciado se alguns de vocês pudessem votar o meu comentário, se você gosta 🙂

Não há necessidade de uma diretiva extra, aqui está minha opinião sobre isso:

HTML:

 
New password is required! New password is not strong enough!
New password confirmation is required! New password confirmation does not match!

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)); }); 

onde Regex.escape () pode ser encontrado aqui .

Funciona como um encanto!

Para adicionar ao grande número de soluções já existentes, isso funciona bem para mim.

( A resposta de Jan Laussmann parou de funcionar com as últimas versões beta do AngularJS).

directiva:

 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; }); } }; }]) 

uso

   

erro de exibição

 
Email addresses don't match.
    Passwords do not match! password errors: { "required": false, "validator": true } 

Isso funcionou para mim.

Directiva:

 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 

Eu tive o mesmo problema quando eu estava tentando construir minha própria diretiva, e eu corrigi com este add

ctrl.$validate();

onde ctrl é meu ngModelController

esta é a minha opinião

   The Password must match  

esta é minha diretiva

 (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: //  // 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(); }); } } })(); 

Algo assim funciona para mim:

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:

   

O princípio Keep It Simple And Stupid (KISS) pode ser útil neste caso. É mais rápido e mais fácil verificar se as duas senhas correspondem, fazendo o seguinte:

 

Do they match? {{signUp.password.$viewValue == signUp.confirmPassword.$viewValue}}

E antes de enviar o formulário, você pode fazer isso no seu 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!'); }; }; }); 

Você pode testá-lo no JSfiddle também.