AngularJs password validation watching issue - angularjs

I have a form with 2 password inputs.
I use a directive to validate that the 2 forms are identical to each other.
It currently works if you fill in the password1 first and the password2 second.
Problem: When you fill in password1 and password2 and they're equal, and after that you change password1, the error messages don't get updated. I would have to type in password2 again for the error messages to appear.
Template
<!-- Password1-->
<div class="form-group"
ng-class="{ 'has-error' : userForm.password.$touched && userForm.password.$invalid,
'has-success' : userForm.password.$valid }">
<div class="col-10">
<input class="form-control" type="password" placeholder="Password"
name="password"
ng-model="home.user.password"
ng-minlength="8"
ng-maxlength="30"
required>
<div class="help-block" ng-messages="userForm.password.$error" ng-if="userForm.password.$touched">
<p ng-message="minlength">Your password is too short.</p>
<p ng-message="maxlength">Your password is too long.</p>
<p ng-message="required">Your password is required.</p>
</div>
</div>
</div>
<!-- Password2-->
<div class="form-group"
ng-class="{ 'has-error' : userForm.password2.$touched && userForm.password2.$invalid,
'has-success' : userForm.password2.$valid }">
<div class="col-10">
<input class="form-control" type="password" placeholder="Confirm your password"
name="password2"
ng-model="home.user.password2"
ng-minlength="8"
ng-maxlength="30"
password-verify="home.user.password"
required>
<div class="help-block" ng-messages="userForm.password2.$error" ng-if="userForm.password2.$touched">
<p ng-message="passwordVerify">Passwords do not match.</p>
</div>
</div>
</div>
passwordVerify directive
.directive('passwordVerify', passwordVerify);
function passwordVerify() {
var directive = {}
directive.require = "ngModel";
directive.scope = { passwordVerify: '=' };
directive.link = verifyPassword;
return directive;
function verifyPassword(scope, element, attrs, ctrl) {
scope.$watch('passwordVerify', WatcherPassword1, callback);
scope.$watch(WatcherPassword2, callback);
function WatcherPassword1() {
var combined;
console.log(scope.passwordVerify);
if (scope.passwordVerify || ctrl.$viewValue) {
combined = scope.passwordVerify + '_' + ctrl.$viewValue;
}
return combined;
}
function WatcherPassword2() {
var combined;
console.log(ctrl.$viewValue);
if (scope.passwordVerify || ctrl.$viewValue) {
combined = scope.passwordVerify + '_' + ctrl.$viewValue;
}
return combined;
}
function callback(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;
}
});
}
}
}
}

I think you need also $watch first input password model in directive
UPDATE
So I found the problem, $watchers areworking good, it was not working because of
ctrl.$parsers.unshift. ctrl.$parsers.unshift executes only if ctrl was modified by user. Check my JSFiddle example
.directive('passwordVerify', passwordVerify);
function passwordVerify() {
return {
require: "ngModel",
scope: {
passwordVerify: '='
},
link: function(scope, element, attrs, ctrl) {
function checkPasswords(){
console.log(viewValue);
var origin = scope.passwordVerify;
if (origin !== ctrl.$viewValue) {
ctrl.$setValidity("passwordVerify", false);
return undefined;
} else {
ctrl.$setValidity("passwordVerify", true);
return ctrl.$viewValue;
}
});
scope.$watch('passwordVerify', function(){
// first input changed
}, function(){
checkPasswords()
})
scope.$watch(function() {
... code here ...
}, function(){
checkPasswords()
})

Related

angular ngMessages custom validation ng-message

I've got this custom validation
function uiEmailEquals() {
return {
require: 'ngModel',
link: function(scope, element, attrs, ngModel) {
scope.$watch(attrs.uiEmailEquals, function() {
ngModel.$validate();
});
ngModel.$validators.isEquals = function(value) {
var email = scope.$eval(attrs.uiEmailEquals);
if (!email || !value) {
return false;
}
return (value === email);
};
}
};
}
<input type="email" tabindex="4" name="cemail" class="form-control" ng-model="vm.data.cemail" placeholder="confirm email" ng-required="true" ui-email-equals="vm.data.email"
/>
<div class="help-block" ng-messages="form.cemail.$error" ng-if="form.cemail.$touched">
<p class="error-message" ng-message="required">Required</p>
<p class="error-message" ng-message="email">Not valid email</p>
<p class="error-message" ng-message="uiemailequals">uiemailequals</p>
<p class="error-message" ng-message="ui-email-equals">ui-email-equals</p>
<p class="error-message" ng-message="uiEmailEquals">uiEmailEquals</p>
<p class="error-message" ng-message="equals">equals</p>
</div>
The problem is I don't find the exp to set inside
ng-message
Can you help me, please ?
ngModel.$validators.isEquals - this is the name of your custom validator -> isEquals
<p class="error-message" ng-message="isEquals">is equals</p>
method name is isEquals use ng-message="isEquals"

How can i write dynamic angularjs directive for validate?

I am newbie in angularjs, and I have a question.
I want to write only a directive for validate all types data (string, number,etc).
I wrote in JSFIDDLE,you can visit here: http://jsfiddle.net/wk8rbot5/5/, it worked.
But I dont want to use if-else to much in this file. I think we can use type or regex from other file. So anyone has suggestion, please let me know. Thank you so much.
var app = angular.module("app",[]);
app.controller("FormCtrl", function($scope) {
$scope.data = {};
$scope.action = function() {
debugger
console.log($scope.data);
}
});
app.directive("allowPattern", function() {
return {
restrict: "A",
require: "ngModel",
link: function(scope, el, attrs, ngModel) {
var validator, patternValidator,
validType = attrs.allowPattern,
required = true;
var pattern = "";
if( validType =="email" ) {
pattern = new RegExp(/^[A-Za-z0-9_-]+([\.]?[A-Za-z0-9_-])*#\w+([-.]\w+)*\.\w+([-.]\w+)*$/);
}
else if(validType =="onlynumber"){
//do other validate here
pattern = new RegExp(/^[0-9]*$/);
} else{
parttern = new RegExp(/^.*S/); // !!! SyntaxError is fixed in this line
}
patternValidator = function(value) {
return validate(pattern, value)
};
ngModel.$formatters.push(patternValidator);
ngModel.$parsers.push(patternValidator);
attrs.$observe("required", function(newval) {
required = newval;
patternValidator(ngModel.$viewValue);
});
function validate(regexp, value) {
if( value == null || value === "" || !required || regexp.test(value) ) { // !!! TypeError: regexp.test is not a function
ngModel.$setValidity('pattern', true);
return value;
}
else {
ngModel.$setValidity('pattern', false);
return;
}
}
}
};
});
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.min.js"></script>
<div ng-app="app" ng-controller="FormCtrl">
<form name="theForm" novalidate="novalidate">
<input type="text" ng-model="data.name" allow-pattern="email" required/>
<button ng-disabled="theForm.$invalid" ng-click="action()">Action</button>
</form>
<br>
other form:
<br>
<form name="theForm2" novalidate="novalidate">
<input type="text" ng-model="data.number" allow-pattern="onlynumber" required/>
<button ng-disabled="theForm2.$invalid" ng-click="action2()">Action</button>
</form>
<br>
other form 3 :
<br>
<form name="theForm3" novalidate="novalidate">
<input type="text" ng-model="data.abc" allow-pattern="" required/>
<button ng-disabled="theForm3.$invalid" ng-click="action3()">Action</button>
</form>
</div>

issue with custom directive for checking unique email id

I am working on Angularjs form where i need to validate whether input value is on database or not.
my html is as below
<div class="form-group mg-btm0" show-errors>
<label class="control-label col-sm-4 fw-norm txt-right">Email ID:</label>
<div class="col-sm-8">
<input type="email" class="form-control" placeholder="Email ID" name="emailAddress" ng-required="true" autocomplete="Off" ng-model="User.emailId"
ng-maxlength="100" emailid-available-validator>
<span class="help-block" ng-if="RegisterUser.emailAddress.$error.email">A valid email is required.</span>
<span class="help-block" ng-if="RegisterUser.emailAddress.$error.maxlength">Max length is 100.</span>
<span class="help-block" ng-if="RegisterUser.emailAddress.$pending"> Checking emailId...</span>
<span class="help-block" ng-if="RegisterUser.emailAddress.emailidAvailable">EmailId entered has already been registered</span>
</div>
</div>
Directive is as below
angularFormsApp.directive('emailidAvailableValidator', ['$http', function ($http) {
var baseurl = window.location.protocol + "//" + window.location.host + "/";
return {
require: 'ngModel',
link: function ($scope, element, attrs, ngModel) {
ngModel.$asyncValidators.emailidAvailable = function (value) {
//var emailid = { 'emailid': emailaddress };
return $http.get(baseurl + "Users/CheckExternalUserExists/", { emailid: value });
};
}
}
}])
and controller is as below
[HttpGet]
public ActionResult CheckExternalUserExists(string emailid)
{
if (AccountExecutor.UserExists(emailid))
{
return new HttpStatusCodeResult(HttpStatusCode.InternalServerError, "Exists");
}
return new HttpStatusCodeResult(HttpStatusCode.OK, "Not Exists");
}
Now problem I am having are.
1 . Email id being pass as null to controller.
2 . I want to show two message
a) If email id is unique , then message should say its unique something
b) if email id exists then It should show message that it exists ,
currently message is not being display only red border is showing.
try below in your code
ngModel.$asyncValidators.emailidAvailable = function (ngModel.$modelValue) {
//var emailid = { 'emailid': emailaddress };
return $http.get(baseurl + "Users/CheckExternalUserExists/", { emailid: value });
};
check out below link for more information...
[asyncValidators][1]

Communication between directive and controller angularjs

I would like to know if it is possible to send the user some kind of error message when the email already exist.
I have some directive like this. :
(function() {
angular
.module('app')
.directive('emailNotUsed',emailNotUsed);
emailNotUsed.$inject = ['$http', '$q'];
function emailNotUsed ($http, $q) {
return {
require: 'ngModel',
link: function(scope, element, attrs, ngModel) {
ngModel.$asyncValidators.emailNotUsed = function(modelValue, viewValue) {
return $http.post('/email',viewValue).then(function(response) {
console.log(response);
return response.data == true ? /*$q.reject(response.data.errorMessage)*/ console.log("Show Error Message"): true;
// console.log(response);
});
};
}
};
}
}());
As you can see this returns Show error in the console. But is it possible to pass this value to the register controller ? And set the value to true or false ?
(function () {
'use strict';
angular
.module('app')
.controller('RegisterController', RegisterController);
RegisterController.$inject = ['UserService', '$http','$q' ];
function RegisterController(UserService, $http,$q) {
var vm = this;
vm.register = register;
function register() {
vm.dataLoading = true;
UserService.Create(vm.user)
}
}
})();
Or could i give an error messages directly into the html.
<div class="container" ng-controller="RegisterController as vm">
<div class="col-md-6 col-md-offset-3">
<div ng-show="vm.error" class="alert alert-danger">{{vm.error}}</div>
<form name="form" ng-submit="!form.$pending && form.$valid && vm.register()" role="form">
<div>
<label for="email">Email</label>
<input type="text" name="email" id="email" class="form-control" ng-model="vm.user.email" email-not-used ng-model-options="{ debounce: 500 }" required >
</div>
<div class="form-actions">
<button type="submit" ng-disabled="form.$invalid || vm.dataLoading" class="btn btn-primary">Register</button>
Cancel
</div>
</form>
</div>
</div>
My solution
After alot of struggling today i found a solution for my problem.
I modified the emailNotUsed directive to emailValidator.
(function() {
angular
.module('app')
.directive('emailValidator',emailValidator);
emailValidator.$inject = ['$q', '$timeout','$http'];
function emailValidator ($q, $timeout,$http){
return {
require: 'ngModel',
link: function(scope, element, attrs, ngModel) {
ngModel.$asyncValidators.email = function(modelValue, viewValue) {
var deferred = $q.defer();
DoesEmailExist()
function DoesEmailExist () {
$http.post('/email',viewValue).then(function(response) {
if (response.data==true) {
console.log('Email does exist')
deferred.reject();
}else {
deferred.resolve();
}
});
};
console.log(deferred.promise)
return deferred.promise;
};
}
}
}
}());
And in registration.html i added this :
<div class="form-group" ng-class="{ 'has-error': form.email.$dirty && form.email.$invalid }">
<label for="email"> Email</label>
<input type="text" ng-model="signup.email" ng-model-options="{ debounce: 500 }" name="email" id="email" class="form-control" required email-validator>
<div class="help-block" ng-messages="form.email.$error" ng-if="form.email.$dirty">
<p ng-message="required">Your name is required.</p>
<div ng-message="email" class="help-block" >email already in use</div>
</div>
Yes you can directly show error message into the HTML.
try this,
In HTML,
<form name="form" ng-submit="!form.$pending && form.$valid && vm.register()" role="form">
<div>
<label for="email">Email</label>
<input type="text" name="email" id="email" class="form-control" ng-model="vm.user.email" email-not-used ng-model-options="{ debounce: 500 }" required >
<span ng-show="form.email.$invalid && form.email.$dirty">Email is already in use!</span>
<span ng-show="form.email.$valid && form.email.$dirty">Email available!</span>
</div>
<div class="form-actions">
<button type="submit" ng-disabled="form.$invalid || vm.dataLoading" class="btn btn-primary">Register</button>
Cancel
</div>
</form>
In app.js,
var app = angular.module('app', []);
app.directive('emailNotUsed',emailNotUsed);
emailNotUsed.$inject = ['$http', '$q'];
function emailNotUsed ($http, $q) {
return {
require: 'ngModel',
link: function(scope, element, attrs, ngModel) {
ngModel.$asyncValidators.emailNotUsed = function(modelValue, viewValue) {
var data='';
if (viewValue=='abc#xyz.com'){
ngModel.$setValidity('valid', false);
scope.form.email.$setValidity('email', false);
}else{
ngModel.$setValidity('valid', true);
scope.form.email.$setValidity('email', true);
}
return data;
}
}
}
}
app.controller('RegisterController', RegisterController);
RegisterController.$inject = ['$scope', '$http','$q' ];
function RegisterController($scope, $http,$q) {
var vm = this;
$scope.name = 'abc#xyz.com email is already in use ';
vm.register = register;
function register() {
vm.dataLoading = true;
UserService.Create(vm.user)
}
}
Hope this helps. .
You can setup error message directly in your view. Bind to $scope.form.email.emailNotUsed.
<div>
<label for="email">Email</label>
<input type="text" name="email" id="email" class="form-control" ng-model="vm.user.email" email-not-used ng-model-options="{ debounce: 500 }" required >
<span ng-show="form.email.emailNotUsed">Email is already in use!</span>
</div>

Angular setValidity not working?

I first using setValidity to make a directive in Angular.but not as my expected,here is my code:
angular.module('myApp', [])
.controller('ctrl',function($scope){
$scope.pw='';
})
.directive('pwCheck', function(){
return {
require: 'ngModel',
link: function (scope, elem, attrs, ctrl) {
elem.on('keyup', function () {
scope.$apply(function () {
var len = elem.val().length;
if(len===0){
ctrl.$setValidity('zero',true);
} else if(len>1 && len<6){
ctrl.$setValidity('one',true);
} else {
ctrl.$setValidity('two',true);
}
});
});
}
};
});
HTML:
<body ng-controller="ctrl">
<form id="myForm" name="myForm">
<input type="text" ng-model="pw" pw-check />
{{myForm.$error}}
<div class="msg-block" ng-show="myForm.$error">
<span class="msg-error" ng-show="myForm.pw.$error.zero">
Input a password.
</span>
<span class="msg-error" ng-show="myForm.pw.$error.one">
Passwords too short.
</span>
<span class="msg-error" ng-show="myForm.pw.$error.two">
Great.
</span>
</div>
</form>
</body>
Online Demo:
http://jsbin.com/cefecicu/1/edit
I think you need:
//Reset your validity
ctrl.$setValidity('zero',true);
ctrl.$setValidity('one',true);
ctrl.$setValidity('two',true);
if(len===0){
ctrl.$setValidity('zero',false);
} else if(len>=1 && len<6){ //use len>=1 instead
ctrl.$setValidity('one',false);
} else {
ctrl.$setValidity('two',false);
}
Using false to indicate errors (not valid):
And give a name to your input:
<input type="text" ng-model="pw" name="pw" pw-check />
http://jsbin.com/cefecicu/11/edit

Resources