app.directive("pwCheck", function () {
alert('hey');
return {
require: 'ngModel',
link: function (scope, elem, attrs, ctrl) {
var firstPassword = '#' + attrs.pwCheck;
elem.add(firstPassword).on('keyup', function () {
scope.$apply(function () {
// console.info(elem.val() === $(firstPassword).val());
ctrl.$setValidity('pwmatch', elem.val() === $(firstPassword).val());
});
});
}
}
});
I have a signup form and users must to input a password and a confirm password, My problem is my directive is not working in validating the password in confirm password to check if the password are the same, Is there another way to implement this validation like ng-pattern to check if the inputs are the same?Thanks in advance.
A better approach is to the $validators pipeline. However, this is also implemented in a form of a directive. This feature was introduced in Angular 1.3. The old fashion way was to use $parsers and / or $formatters. The huge advantage of the validators pipeline is that you have access to both, viewValue and modelValue. Just pass the password to the directive and add a new validator.
var app = angular.module('myApp', []);
app.controller('TestCtrl', TestController);
function TestController() {
var vm = this;
vm.password = '';
vm.confirmPassword = '';
}
app.directive('confirmPassword', ConfirmPassword);
function ConfirmPassword() {
var linkFn = function(scope, element, attributes, ngModel) {
ngModel.$validators.confirmPassword = function(modelValue) {
return modelValue == scope.password;
};
scope.$watch("password", function() {
ngModel.$validate();
});
};
return {
require: "ngModel",
scope: {
password: "=confirmPassword"
},
link: linkFn
};
};
input {
display: block;
margin-top: 5px;
margin-bottom: 10px;
}
.error {
color: red;
font-weight: bold;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
<div ng-app="myApp" ng-controller="TestCtrl as testCtrl">
<form name="myForm">
<label for="password">Password</label>
<input id="password" name="password" ng-model="testCtrl.password" type="password" />
<label for="confirmPassword">Confirm Password</label>
<input id="confirmPassword" name="confirmPassword" ng-model="testCtrl.confirmPassword" data-confirm-password="testCtrl.password" type="password" />
<span class="error" ng-show="myForm.confirmPassword.$invalid && !myForm.confirmPassword.$pristine">Passwords do not match!</span>
</form>
</div>
This will check if both passwords are matching. If the passwords do not match the validity will be false. In this case I display an error message.
Related
I'm trying to validate two password input fields. Simply confirm that they are equal. (Suggest another approach if mine is way wrong)
I have implemented a directive with a simple validation that checks if the "confirm" password is the same as the original. But the directive also checks for other things, so I need to have both input fields to have it.
The problem is that when I have my directive on both input fields, I cannot read their model values through the attribute (to check if they match).
Here is a working demo without the directive on the first password:
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
});
app.directive('myDir', function() {
return {
require: 'ngModel',
link: function(scope, elem, attrs, ctrl) {
ctrl.$validators.mismatch = function(modelValue, viewValue) {
// MAIN CODE:
return viewValue === scope.$eval(attrs.confirm);
};
ctrl.$validators.short = function(modelValue, viewValue) {
if (ctrl.$isEmpty(modelValue)) {
return true;
}
if (modelValue.length >= 3) {
return true;
}
return false;
}
}
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.7/angular.min.js"></script>
<div ng-app="myApp" ng-controller="myCtrl">
<form name="form1">
<input type="password" name="password1" ng-model="pass1"><br>
<input type="password" my-dir confirm="pass1" name="password2" ng-model="pass2"><br>
<pre>{{form1.password2.$error | json}}</pre>
<p ng-show="form1.password2.$error.mismatch" style="color:red">Passwords are different</p>
</form>
</div>
If I change the first filed to:
<input type="password" my-dir confirm="pass2" name="password1" ng-model="pass1">
to validate in both directions, then scope.$eval(attrs.confirm) becomes undefined for both fields.
Here is a demo of my issue:
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
});
app.directive('myDir', function() {
return {
require: 'ngModel',
link: function(scope, elem, attrs, ctrl) {
ctrl.$validators.mismatch = function(modelValue, viewValue) {
// `scope.$eval(attrs.confirm)` always undefined
return viewValue === scope.$eval(attrs.confirm);
};
ctrl.$validators.short = function(modelValue, viewValue) {
if (ctrl.$isEmpty(modelValue)) {
return true;
}
if (modelValue.length >= 3) {
return true;
}
return false;
}
}
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.7/angular.min.js"></script>
<div ng-app="myApp" ng-controller="myCtrl">
<form name="form1">
<input type="password" my-dir confirm="pass2" name="password1" ng-model="pass1"><br>
<input type="password" my-dir confirm="pass1" name="password2" ng-model="pass2"><br>
<pre>{{form1.password2.$error | json}}</pre>
<p ng-show="form1.password2.$error.mismatch || form1.password.$error.mismatch" style="color:red">
Passwords are different
</p>
</form>
</div>
You need to do 2 things:
1. Add ng-model-options="{allowInvalid: true}" so invalid value will still update scope value.
2. Now you have problem that e.g. changing 2nd input wont trigger 1st re-validation. This is done using observe:
<body ng-controller="MainCtrl" ng-init="x = 0; y = 0">
<form name="form1">
<input type="password" my-dir="{{y}}" confirm="pass2" name="password1" ng-model="pass1" ng-model-options="{allowInvalid: true}"
ng-change="x = x + 1"><br>
<input type="password" my-dir="{{x}}" confirm="pass1" name="password2" ng-model="pass2" ng-model-options="{allowInvalid: true}"
ng-change="y = y + 1"><br>
and
attrs.$observe('myDir', function() {
ctrl.$validate();
});
http://plnkr.co/edit/ws4tVWGXfFNR2yqLRJN7?p=preview
P.S. for usual fields I would write my-dir="{{pass1}}" and then no need in $eval and ng-change, but for passwords... not sure
I have a form where the user needs to enter 2 times his email.
I found on the internet (but not able to find the link anymore) some angular code doing what I wanted.
The only issue is when the 2 emails are the same, one input still got the class
.ng-invalid.ng-dirty
So I can't submit the form.
My code is the following:
css:
.ng-invalid.ng-dirty{
border-color: #FA787E;
}
.ng-valid.ng-dirty{
border-color: #78FA89;
}
html:
<div ng-app="myApp">
<form name="formTemplate" novalidate>
<input id="email1" type="email" ng-model="currentForm.email1" name="email1" required>
<span ng-show="formTemplate.email1.$error.required && formTemplate.email1.$dirty">required</span>
<span ng-show="!formTemplate.email1.$error.required && formTemplate.email1.$error.email1 && formTemplate.email1.$dirty">invalid email</span>
<input id="email2" type="email" name="email2" ng-model="currentForm.email2" same-email required>
<span ng-show="formTemplate.email2.$error.required && formTemplate.email2.$dirty">Please confirm your email.</span>
<span ng-show="!formTemplate.email2.$error.required && formTemplate.email2.$error.noMatch && formTemplate.email1.$dirty">Emails do not match.</span>
</form>
</div>
javascript:
var app = angular.module('myApp', ['UserValidation']);
angular.module('UserValidation', []).directive('sameEmail', function () {
return {
require: 'ngModel',
link: function (scope, elm, attrs, ctrl) {
ctrl.$parsers.unshift(function (viewValue, $scope) {
var noMatch = viewValue != scope.formTemplate.email1.$viewValue;
ctrl.$setValidity('noMatch', !noMatch)
})
}
}
})
Here a jsfiddle: http://jsfiddle.net/malamine_kebe/pq6fw04v/
Im update your jsfiddle. You don't return value from ctrl.$parsers.unshift.
ctrl.$parsers.unshift(function (viewValue, $scope) {
var noMatch = viewValue != scope.formTemplate.email1.$viewValue;
ctrl.$setValidity('noMatch', !noMatch);
return noMatch;
})
Updated jsfiddle
I have the following AngularJS code. It should check if input field is empty when I press Submit button. Submit button broadcasts custom event that directive successfully catches. But it doesn't work when field is empty. It reaches ctrl.$parsers.unshift when I start typing and my field becomes theForm.name.$invalid===true. It seems to work the opposite way.
define(['angular'], function (angular) {
"use strict";
var requiredValidator = angular.module('RequiredValidator', []);
requiredValidator.directive('validateRequired', function () {
var KEY_ERROR = "required";
return {
scope: {
validateRequired: '=validateRequired'
},
require: 'ngModel',
link: function (scope, elem, attr, ctrl) {
function validate(value) {
var valid = !value || value === '' || value === null;
ctrl.$setValidity(KEY_ERROR, valid);
return value;
}
scope.$on('validateEvent', function (event, data) {
if (scope.validateRequired.$submitted) {
console.log("Reachable block when submitted");
ctrl.$parsers.unshift(function (value) {
console.log("Unreachable when input is empty");
return validate(value);
});
ctrl.$formatters.unshift(function (value) {
return validate(value);
});
}
});
}
};
});
return requiredValidator;
});
Form field snippet:
<div>
<input type="text" name="name"
data-ng-class="{ error : theForm.name.$invalid}"
data-ng-model="customer.name"
data-validate-required="theForm">
<span data-ng-show="theForm.name.$invalid" class="error">{{getInputErrorMessage(theForm.name.$error)}}</span>
</div>
You actually don't need such a complex directive for your szenario. You could also handle the logic within a controller like so:
var app = angular.module('form-example', ['ngMessages']);
app.controller('FormCtrl', function($scope) {
var vm = this;
vm.submit = function(form) {
if (form.$invalid) {
angular.forEach(form.$error.required, function(item) {
item.$dirty = true;
});
form.$submitted = false;
} else {
alert('Form submitted!');
}
};
});
label,
button {
display: block;
}
input {
margin: 5px 0;
}
button {
margin-top: 10px;
}
form {
margin: 10px;
}
div[ng-message] {
margin-bottom: 10px;
color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.15/angular-messages.js"></script>
<form ng-app="form-example" name="myForm" ng-controller="FormCtrl as vm" novalidate="" ng-submit="vm.submit(myForm)">
<label for="username">Username</label>
<input id="username" type="text" name="username" ng-model="vm.username" required="" />
<div ng-messages="myForm.username.$error" ng-if="myForm.username.$dirty" role="alert">
<div ng-message="required">Username is required</div>
</div>
<label for="email">E-Mail</label>
<input id="email" type="email" name="email" ng-model="vm.email" required="" />
<div ng-messages="myForm.email.$error" ng-if="myForm.email.$dirty" role="alert">
<div ng-message="required">E-Mail is required</div>
<div ng-message="email">Your E-Mail is not valid</div>
</div>
<button type="submit">Send</button>
</form>
This requires to use at least AngularJS version 1.3.0 since I use the $submitted property of the internal FormController. For more information check the documentation on the FormController. I also use ngMessages which was also introduced in 1.3. This is pretty helpful if you want to display messages in forms in respect to errors.
I created a directive that check if an input is valid based on some criteria. In this form I have a button that is ng-disabled="form.$invalid". The problem is that, even if it seems like the valid state is populated, my button is not enabled when my custom directive change the validity state of the input.
Here is a simple example:
<div ng-app="app">
<div ng-controller="fooController">
<form name="fooForm">
<input type="text" ng-model="foo" foo>
<input type="submit" value="send" ng-disabled="fooForm.$invalid">
</form>
</div>
</div>
JS (CoffeeScript):
app = angular.module 'app', []
app.directive 'foo', ->
restrict: 'A'
require: 'ngModel'
link: (scope, element, attrs, controller) ->
element.bind 'keyup', ->
if controller.$viewValue isnt 'foo'
controller.$setValidity 'foo', false
else
controller.$setValidity 'foo', true
app.controller 'fooController', ($scope) ->
$scope.foo = 'bar'
In short, this directive check if the input's value === 'foo'. If it's not it sets the validity 'foo' to false, otherwise to true.
Here is a jsfiddle (javascript) : http://jsfiddle.net/owwLwqbk/
I found a solution involving $apply: http://jsfiddle.net/owwLwqbk/1/
But I wonder if there's not an other, a better way of doing it? Isn't the state supposed to populate?
The jqLite event handler runs outside the context of Angular, that's why you needed the scope.$apply() before it would work.
Another option is to use a watch...
link: function(scope, element, attrs, controller) {
scope.$watch(function () {
return controller.$viewValue;
}, function (newValue) {
controller.$setValidity('foo', newValue === 'foo');
});
}
Fiddle
Please see demo below
var app;
app = angular.module('app', []);
app.directive('foo', function() {
return {
restrict: 'A',
require: 'ngModel',
link: function(scope, element, attrs, ctrl) {
ctrl.$parsers.unshift(function(val) {
console.log(val);
if (val == "bar") {
ctrl.$setValidity('foo', true);
} else {
ctrl.$setValidity('foo', false);
}
});
}
};
});
app.controller('fooController', function($scope) {
$scope.foo = 'bar';
});
.ng-invalid-foo {
outline: none;
border: 1px solid red;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app">
<div ng-controller="fooController">
[Only "bar" is valid value] <br/>
<form name="fooForm">
<input type="text" ng-model="foo" foo="">
<input type="submit" value="send" ng-disabled="fooForm.$invalid" />
</form>
</div>
</div>
I have a form with input fields and have a custom directive for each input field to validate the data entered by user.Requirement is that when user leaves the input field with invalid data, error message to be displayed.However, few of the fields are optional that if User skips with out entering any data for these fields, no Validation is required.
I tried to implement this using Blur event in the directive, but this is causing the vaidation called even in case of no data entered.
Please advise if Watch function can be used here and any sample snippet here would be appreciated. I have written code in a fiddle which is similar to my directive for one of the input field that checks minimum length (although there is a built-in directive, taken this as an example).This fiddle can be accessed at http://jsfiddle.net/4xbv0tgL/49/
<div ng-app="myApp" ng-controller="myCtrl">
<form name="myForm">
Num1: <input type="text" ng-model="num1" my-min-length="5" name="num1" />
<span class="error" ng-hide="myForm.num1.$valid"
ng-show="myForm.num1.$error">Invalid Number!</span>
<br />
Num2: <input type="text" ng-model="num2" my-min-length="5" name="num2" />
<span class="error" ng-hide="myForm.num2.$valid"
ng-show="myForm.num2.$error">Invalid Number!</span>
</form>
</div>
var myApp = angular.module("myApp", []);
var myCtrl = myApp.controller("myCtrl",["$scope", function($scope) {
$scope.num1 = "12345";
$scope.num2 = "55555";
}]);
myApp.directive("myMinLength", function () {
return {
restrict: "A",
require: "ngModel",
link: function (scope, element, attr, ngModelCtrl) {
var minlength = Number(attr.myMinLength);
var inputparse = function (inputtext) {
if ((inputtext.length >= minlength) && (!isNaN(inputtext))) {
return inputtext;
}
return undefined;
}
ngModelCtrl.$parsers.push(inputparse);
element.bind("blur", function () {
var value = inputparse(element.val());
var isValid = !!value;
if (isValid) {
ngModelCtrl.$setViewValue(value);
ngModelCtrl.$render();
}
ngModelCtrl.$setValidity("myMinLength", isValid);
scope.$apply();
}
);
}
};
});
I think you are over complicating life for yourself. Why don't you just use multiple directives for multiple checks?
<div ng-app="myApp"
ng-controller="myCtrl">
<form name="myForm"
novalidate>
Num1:
<input type="text"
ng-model="num1"
ng-minlength="5"
integer
name="num1"
required/>
<span class="error"
ng-show="myForm.num1.$invalid&&myForm.num1.$touched">Invalid Number!</span>
</form>
</div>
And here's the integer directive:
var INTEGER_REGEXP = /^[0-9]*$/;
myApp.directive('integer', function () {
return {
require: 'ngModel',
link: function (scope, elm, attrs, ctrl) {
ctrl.$parsers.unshift(function (viewValue) {
if (viewValue === "") {
ctrl.$setValidity('integer', true);
return viewValue;
} else if (INTEGER_REGEXP.test(viewValue)) {
ctrl.$setValidity('integer', true);
return viewValue;
} else {
ctrl.$setValidity('integer', false);
return viewValue;
}
});
}
};
});
Just be sure that you are using angular 1.3 or a newer version. Because $touched and $untouched don't exist in 1.2.