Reputation: 285
What I am trying to do is create a directive which compares two password inputs and triggers invalid if either changes. I have found a few examples and have tried a few and have combined a few in my own attempts. However, I have only been able to toggle the validity with $setValidity when the confirm password field changes. When you change the password field it doesn't trigger the invalidity of the comparison.
Here's my directive:
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 + '_' + scope.$view;
}
return combined;
}, function(value) {
if (value) {
ctrl.$parsers.unshift(function(viewValue) {
var origin = scope.passwordVerify;
if (origin !== viewValue) {
ctrl.$setValidity("pwd", false);
return undefined;
} else {
ctrl.$setValidity("pwd", true);
return viewValue;
}
});
}
});
}
};
});
Here's the directive in action:
<input id="user_password" type="password" name='user_password' placeholder="password" value='' required ng-model="user.user_password">
<p class="help-text">Required</p>
<div class="help-block" ng-messages="add_user_form.user_password.$error" ng-show="add_user_form.user_password.$touched">
<div ng-messages-include="/app/views/messages.html" ></div>
<input id="confirm_password" ng-model="user.confirm_password" name="confirm_password" type="password" placeholder="confirm password" name="user_confirm_password" required password-verify="user.user_password">
<p class="help-text">Enter matching password</p>
<div class="help-block" ng-messages="add_user_form.confirm_password.$error" ng-show="add_user_form.confirm_password.$touched">
<div ng-messages-include="/app/views/messages.html" ></div>
With this code I can verify that the passwords match when I change the value of the confirm password field, however when you change the value of the password field it doesn't revalidate the input. I'm pretty sure there is a successful way to add $watch to two elements or to use $watchgroup to do this. I just can't figure it out. I know there are a lot of questions on this topic but all I've tried have only gotten me to this point.
I'm using Angular 1.5.7 btw...
Upvotes: 0
Views: 1070
Reputation: 24874
Here's a version working bi-directionally:
(function() {
"use strict";
angular.module('app', ['ngMessages'])
.controller('mainCtrl', function($scope) {
})
.directive('passwordVerify', 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('passwordVerify', function(val) {
validate();
});
var validate = function() {
// values
var val1 = ngModel.$viewValue;
var val2 = attrs.passwordVerify;
// set validity
ngModel.$setValidity('passwordVerify', !val1 || !val2 || val1 === val2);
};
}
}
})
})();
<html ng-app="app">
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.7/angular.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/css/bootstrap.min.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-messages/1.5.7/angular-messages.min.js"></script>
</head>
<body ng-controller="mainCtrl">
<form name="add_user_form">
<div class="col-md-12">
<div class="form-group" ng-class="{ 'has-error' : add_user_form.user_password.$touched && add_user_form.user_password.$invalid }">
<p class="help-text">Enter password</p>
<input type="password" class="form-control" id="user_password" name="user_password" placeholder="password" required ng-model="user.user_password" password-verify="{{user.confirm_password}}">
<div class="help-block" ng-messages="add_user_form.user_password.$error" ng-show="add_user_form.user_password.$touched">
<p ng-message="required">This field is required</p>
<p ng-message="minlength">This field is too short</p>
<p ng-message="maxlength">This field is too long</p>
<p ng-message="required">This field is required</p>
</div>
</div>
<div class="form-group" ng-class="{ 'has-error' : add_user_form.confirm_password.$touched && add_user_form.confirm_password.$invalid }">
<p class="help-text">Enter matching password</p>
<input class="form-control" id="confirm_password" ng-model="user.confirm_password" name="confirm_password" type="password" placeholder="confirm password" required password-verify="{{user.user_password}}">
<div class="help-block" ng-messages="add_user_form.confirm_password.$error" ng-show="add_user_form.confirm_password.$touched">
<p ng-message="required">This field is required</p>
<p ng-message="minlength">This field is too short</p>
<p ng-message="maxlength">This field is too long</p>
<p ng-message="required">This field is required</p>
<p ng-message="passwordVerify">No match!</p>
</div>
</div>
</div>
</form>
</body>
</html>
I hope it helps.
Upvotes: 1