angular ngMessages custom validation ng-message - angularjs

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"

Related

AngularJs password validation watching issue

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

Password Confirmation Directive

Here is the code I'm using for the directive:
var compareTo = function() {
return {
require: "ngModel",
scope: {
otherModelValue: "=compareTo"
},
link: function(scope, element, attributes, ngModel) {
ngModel.$validators.compareTo = function(modelValue) {
console.log(modelValue + ":" + scope.otherModelValue);
return modelValue == scope.otherModelValue;
};
scope.$watch("otherModelValue", function() {
ngModel.$validate();
});
}
};
};
app.directive("compareTo", compareTo);
Here is my html:
<div class="form-group">
<label>Password</label>
<span>Must contain at least eight characters, including uppercase, lowercase letters and numbers</span>
<input type="password"
class="form-control"
name="password"
ng-model="signUpPass1"
ng-pattern="/^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.{8,})/"
required>
<div ng-messages="signUpForm.password.$error" class="formMsgContainer">
<span class="formMsg" ng-message="pattern">Passwords Does Not Meet the Criterias!</span>
</div>
</div>
<div class="form-group">
<label>Confirm Password</label>
<input type="password"
class="form-control"
name="conPass"
ng-model="signUpPass2"
compare-to="signUpPass1"
required>
<div ng-messages="signUpForm.conPass.$error" class="formMsgContainer">
<span class="formMsg" ng-message="compareTo">Passwords Do Not Match!</span>
</div>
</div>
However the compareTo directive doesn't work. Looking at the console log I put in the directive, it prints out the string for pass2 and undefined for pass1. Such as aaaa:undefined. This means that they will never be equal and thus there will always be an error. So there must be something wrong with the statement scope.otherModelValue but I can't seem to figure out what is wrong.
Thanks
Try this directive. I haven't tested it, so if it doesn't work, please tell me.
app.directive("compareTo", function() {
return {
require: "ngModel",
link: function(scope, element, attributes, controller) {
scope.$watch(attributes.ngModel, function(value) {
controller.$setValidity('compare', (element.val() === value));
});
}
};
});
You can then use the "compare" in the ng-message to output an error.
To create your own checks try directive use-form-error. It is easy to use and will save you a lot of time.
Live example jsfiddle
<form name="ExampleForm">
<label>Password</label>
<input ng-model="password" required />
<br>
<label>Confirm password</label>
<input ng-model="confirmPassword" required />
<div use-form-error="isSame" use-error-expression="password && confirmPassword && password!=confirmPassword" ng-show="ExampleForm.$error.isSame">Passwords Do Not Match!</div>
</form>

AngularJS: How to set validity based on custom boolean value

I would like to set the validity of a form element based on a custom boolean value. Consider the following password fields:
<input type="password" name="password" ng-model="user.password" required>
<input type="password" name="passwordRepeat" ng-model="user.passwordRepeat" required>
I would like to mark the second input field valid if the repeated password matches the original password. Something like:
<input type="password" name="passwordRepeat" ng-model="user.passwordRepeat" my-validation-check="user.passwordRepeat === user.password" required>
I was not able to find any Angular directive for this purpose. Any ideas? Perhaps create my own directive for this? Unfortunately, I'm not an Angular expert... it should be something like this:
angular.module('app').directive('myValidationCheck', function() {
return {
scope: true,
require: 'ngModel',
link: function(scope, elm, attrs, ngModel) {
// eval and watch attrs.myValidationCheck
// and use ngModel.$setValidity accordingly
}
};
});
Thanks!
I have spent quite a bit of time finding the best answer based on your answers below (thanks a lot!). What did the trick for me was simply:
angular.module('myApp').directive('myValidationCheck', function() {
return {
scope: {
myValidationCheck: '='
},
require: 'ngModel',
link: function(scope, elm, attrs, ngModel) {
scope.$watch('myValidationCheck', function(value) {
ngModel.$setValidity('checkTrue', value ? true : false);
});
}
};
});
for
<input type="password" name="passwordRepeat" my-validation-check="user.password === user.passwordRepeat" ng-model="user.passwordRepeat" required>
And this is really flexible. You can use anything you want in my-validation-check, e.g. make sure a checkbox is checked or any more complex expression is true.
Hope this helps not just myself.. :-)
Why do you need special directive for it?
Why not make so:
<div ng-controller="MyCtrl">
<form name="myForm" ng-submit="processForm()">
<input type="password" ng-model="password" placeholder="password" required/>
<input type="password" ng-model="repeatedPassword" placeholder="repeat password" required/>
<input type="Submit" value="Submit" ng-disabled="passwordsMissmatched()"/>
<span ng-show="passwordsMissmatched()">
Password mismatched
</span>
</form>
</div>
And your JS:
function MyCtrl($scope) {
$scope.passwordsMissmatched = function(){
return $scope.password && $scope.repeatedPassword
&& ($scope.password != $scope.repeatedPassword);
}
$scope.processForm = function(){
if($scope.password == $scope.repeatedPassword){
alert("Form processing..");
}
};
}
This approach should work like a charm.
I've created JSFiddle for you.
Please see demo below
var app = angular.module('app', []);
app.directive('mcheck', function() {
return {
require: 'ngModel',
link: function(scope, elm, attrs, ngModel) {
scope.$watch(attrs.ngModel, function(value) {
if (value == attrs.mcheck) {
ngModel.$setValidity('notEquals', true);
} else {
ngModel.$setValidity('notEquals', false);
}
});
}
};
});
app.controller('fCtrl', function($scope) {
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app">
<div ng-controller="fCtrl">
<form novalidate name="login">
<input type="text" name="password" ng-model="user.password" mcheck="{{user.passwordRepeat}}" required>
<input type="text" name="passwordRepeat" ng-model="user.passwordRepeat" mcheck="{{user.password}}" required>
<HR/>
<span ng-show="login.password.$error.notEquals && login.passwordRepeat.$error.notEquals && login.$dirty">Passwords are not equal</span>
<HR/>
</form>
</div>
</div>

Form Validation not working with ui-boostrap

I'm having a bit of trouble getting the form to run it's validation function. I have a plnkr. I Know I'm close... The validation file is loading in without errors. It's just not running the validation part. I built it off of this. What am I missing? Thanks in advance for the help.
my Form:
<form id="phone" class="content-pad span6" novalidate>
<div class="control-group" ng-class="{error:!input-form-Phone.phonenumber.$valid}">
<label for="phonenumber">Enter Area Code and Telephone Number</label>
<div class="form-group controls">
<input type="text" class="form-control" id="inputphonenumber" name="phonenumber" ng-model="phonenumber"
placeholder="Ex: 4155551234" valid-phonenumber/>
<div class="help-inline">
<span ng-show="!!phone.phonenumber.$error.isBlank">Phone Number Required.</span>
<span ng-show="!!phone.phonenumber.$error.invalidChars">Must Contain Number Only</span>
<span ng-show="!!phone.phonenumber.$error.invalidLen">Phone Number Must Contain area Code and Phone Number.</span>
</div>
</div>
</div>
<div class="form-actions" ng-show="formAllGood()">
<div class="span6">
<a ng-href="SA_report_results.html" class="btn btn-primary " type="button">Run Report</a>
</div>
</div>
<div class="span3" >
<input type="button" value="Reset" ng-click="reloadPage()" class="btn btn-danger "/>
</div>
</form>
app,js
var app = angular.module('myApp', ['myApp.formValidation','ui.bootstrap']);
app.controller('MainCtrl', function($scope) {
$scope.name = 'World';
$scope.formAllGood = function(){
return ($scope.phonenumberGood);
};
});
validation,js
angular.module('myApp.formValidation', [])
.directive('validPhoneNumber', function () {
return {
require: 'ngModel',
link: function (scope, elm, attrs, ctrl) {
ctrl.$parsers.unshift(function (viewValue) {
// Any way to read the results of a "required" angular validator here?
var isBlank = viewValue === '';
var invalidChars = !isBlank && !/^[A-z]+$/.test(viewValue);
var invalidLen = !isBlank && !invalidChars && (viewValue.length < 5 || viewValue.length > 20);
ctrl.$setValidity('isBlank', !isBlank);
ctrl.$setValidity('invalidChars', !invalidChars);
ctrl.$setValidity('invalidLen', !invalidLen);
scope.phonenumberGood = !isBlank && !invalidChars && !invalidLen;
});
}
};
});
You are calling valid-phonenumber which doesn't exist. It is valid-phone-number. This will make your plunker run.
By the way your invalidChars check is wrong.

AngularJS validation directive

We have a validation directive that we use to validate the controls on Blur and viewContentLoaded event.
We persist the form values in local storage to remember the details when we navigate away from the form and come back
The problem is that, even though it remembers the details it doesn't re-validate the Firstname and Lastname when we load that view again.
Following is our original code:
<div>
<form name="form" class="form-horizontal">
<label class="control-label">First name</label>
<div class="controls">
<input id="firstName" name="FirstName" ng-model="order.FirstName" type="text" validate="alphabeticOnly" maxLength="30" required/>
<span class="help-block" ng-show="form.FirstName.$dirty && form.FirstName.$invalid">Please enter valid Firstname</span>
</div>
</div>
<div class="control-group">
<label class="control-label">Last name</label>
<div class="controls">
<input id="lastName" name="LastName" ng-model="order.LastName" type="text" validate="alphabeticOnly" maxLength="30" required/>
<span class="help-block" ng-show="form.LastName.$dirty && form.LastName.$invalid">Please enter valid Lastname</span>
</div>
</div>
</form>
Confirm
The next function just saves the order and redirects to another page.
We have a $watch on $scope.order that saves the data in local storage to remember.
Directive:
.directive('validate', ['validationService', function(validationService) {
function validate(elm) {
var fn = elm.attr("validate");
var value = elm.val();
return validationService[fn](value);
}
return {
restrict: 'A',
require: 'ngModel',
link: function(scope, elm, attrs, ctrl) {
function triggerValidations(){
checkValidity();
ctrl.$parsers.unshift(function(viewValue) {
checkValidity();
return viewValue;
});
ctrl.$formatters.unshift(function(viewValue) {
checkValidity();
return viewValue;
});
}
function checkValidity(){
if (elm.val().length > 0)
{
var isValid = validate(elm);
ctrl.$setValidity('validate', isValid);
console.log(" here i am - CheckValidity", attrs.id, elm.val(), isValid );
//scope.$apply();
}
}
$rootScope.$on('$viewContentLoaded', triggerValidations);
elm.bind('blur', function(event) {
scope.$apply(function() {
ctrl.$setValidity('validate', validate(elm));
});
});
}
};
}])
If we add $scope.apply it gives an error "$digest already in progress"
At the end, we want to validate the form when someone lands onto the page.

Resources