How to do auto tooltip validation msg? - javascript

Here I created sample file for validation, which is working fine...
But My requirement is I need to do some modification on that while validating. Error message need to show in auto tooltip. It needs to be shown automatically when there is error and hide automatically once error cleared. Until error clear popup need to be stay.
If it is possible without jquery or else with jquery also fine.
var app = angular.module('myapp', ['UserValidation']);
myappCtrl = function($scope) {
$scope.formAllGood = function () {
return ($scope.usernameGood && $scope.passwordGood && $scope.passwordCGood)
}
}
angular.module('UserValidation', []).directive('validUsername', 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-z0-9]+$/.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.usernameGood = !isBlank && !invalidChars && !invalidLen
})
}
}
}).directive('validPassword', function () {
return {
require: 'ngModel',
link: function (scope, elm, attrs, ctrl) {
ctrl.$parsers.unshift(function (viewValue) {
var isBlank = viewValue === ''
var invalidLen = !isBlank && (viewValue.length < 8 || viewValue.length > 20)
var isWeak = !isBlank && !invalidLen && !/(?=.*[a-z])(?=.*[A-Z])(?=.*[^a-zA-Z])/.test(viewValue)
ctrl.$setValidity('isBlank', !isBlank)
ctrl.$setValidity('isWeak', !isWeak)
ctrl.$setValidity('invalidLen', !invalidLen)
scope.passwordGood = !isBlank && !isWeak && !invalidLen
})
}
}
}).directive('validPasswordC', function () {
return {
require: 'ngModel',
link: function (scope, elm, attrs, ctrl) {
ctrl.$parsers.unshift(function (viewValue, $scope) {
var isBlank = viewValue === ''
var noMatch = viewValue != scope.myform.password.$viewValue
ctrl.$setValidity('isBlank', !isBlank)
ctrl.$setValidity('noMatch', !noMatch)
scope.passwordCGood = !isBlank && !noMatch
})
}
}
})
<link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.2.2/css/bootstrap-combined.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myapp">
<form name="myform" class="form form-horizontal" ng-controller="myappCtrl" novalidate>
<legend>Angular User Validation with Bootstrap Decorations</legend>
<div class="control-group" ng-class="{error:!myform.username.$valid}">
<label for="inputUsername" class="control-label">Username:</label>
<div class="controls">
<input type="text" id="inputUsername" name="username" ng-model="username" valid-username />
<div class="help-inline">
<span ng-show="!!myform.username.$error.isBlank">Username Required.</span>
<span ng-show="!!myform.username.$error.invalidChars">Username must contain letters & spaces only.</span>
<span ng-show="!!myform.username.$error.invalidLen">Username must be 5-20 characters.</span>
</div>
</div>
</div>
<div class="control-group" ng-class="{error:!myform.password.$valid}">
<label for="inputPassword" class="control-label">Password:</label>
<div class="controls">
<input type="text" id="inputPassword" name="password" ng-model="password" valid-password />
<div class="help-inline">
<span ng-show="!!myform.password.$error.isBlank">Password Required.</span>
<span ng-show="!!myform.password.$error.isWeak">Must contain one upper & lower case letter and a non-letter (number or symbol.)</span>
<span ng-show="!!myform.password.$error.invalidLen">Must be 8-20 characters.</span>
</div>
</div>
</div>
<div class="control-group" ng-class="{error:!myform.password_c.$valid}">
<label for="password_c" class="control-label">Confirm Password:</label>
<div class="controls">
<input type="text" id="password_c" name="password_c" ng-model="password_c" valid-password-c />
<div class="help-inline">
<span ng-show="!!myform.password_c.$error.isBlank">Confirmation Required.</span>
<span ng-show="!!myform.password_c.$error.noMatch">Passwords don't match.</span>
</div>
</div>
</div>
<div class="form-actions" ng-show="formAllGood()">
<input type="submit" class="btn btn-primary" value="Submit" />
</div>
</form></div>

Yes it is possible to show/hide popover on any event. Following code depicts a validate function for numbers using popover.
JSFiddle.
function validate(el) {
var regex = /^\d+$/g;
var valid = regex.test(el.value);
if (!valid) {
// Check if popover is already visible to handle flicker effect.
if ($("#txtInput").next('div.popover').length == 0) {
$('#txtInput').popover({
placement: 'bottom',
content: 'This is not a valid entry'
}).popover('show');
}
} else {
$('#txtInput').popover('hide');
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.2/jquery.min.js"></script>
<link rel="stylesheet" href="http://netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css">
<script src="http://netdna.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js"></script>
<input type="text" id="txtInput" onkeyup="validate(this)">
References:
Check visibility
Documentation.

Best solution is to use Parsley.js
Why Parsley :
Validation Event can be customized (onsubmit , onkeyup , or any other event )
Validation Style can be customized
Validation message will automatically disappear , once input satisfies conditions
Check their examples

Related

AngularJS confirmation password validations

Here i am facing the problem regarding below specified third point (when user changes password value).
Test Scenario:
user enters all field properly - [Button Enabled]
if password field is invalid as it doesn't meet the password strength then the create an account button is in disable mode.
If user changes password value but the password field is valid. EX: [Yash#123 to Yash#1234]
here confirmation field value is Yash#123. then button should be in disable mode.
I have tested by accessing Parent Scope, Scope values between two directives like this.
function okPasswordDirective() {
$element.on('blur change keydown', function( evt ) {
if( ngPasswordModel.$valid ) {
$scope.passwordVal = ngPasswordModel.$viewValue;
console.log('Updated Val : ', $scope.passwordVal);
$scope.updatePass();
}
}
}
function compareToDirective() {
//use scope.$parent to associate the function called to directive function
scope.$parent.updatePass = function() {
console.log('$watch « Password Element Watcher.')
console.log('Pswd: ',scope.$parent.passwordVal, '\t Cnfirm:', ngModel.$modelValue);
//scope.registerForm.confirm.$invalid = true;
}
}
Here in updatePass() function iam not receiving the lastcommited value of password. When i click on confirm field it used to get.
but no use, i am unable to disable the button by making confirm field as invalid.
var pswd = angular.element(document.getElementById('password')).scope().registerForm.password;
var cnfm = angular.element(document.getElementById('confirmedID')).scope().registerForm.confirm;
console.log('PSWD:', pswd, '\n CNFM:', cnfm);
console.log('Diff : ', pswd.$viewValue != cnfm.$viewValue);
if( pswd.$viewValue != cnfm.$viewValue ) {
console.log('Result : ', (pswd.$dirty && cnfm.$dirty && cnfm.$valid && ( pswd.$viewValue != cnfm.$viewValue ) ) ? 'error' : 'noErr');
cnfm.$invalid = true;
}
Registration Form Code: fiddle
<!-- HTML CODE -->
<body ng-app="loginModule">
<div class="main-container">
<div class="form-container">
<h2 class="form-label">Sign Up</h2>
<div class="form-container" data-ng-controller="registerController" >
<form name="registerForm" role="form" data-ng-submit="formSubmit()">
<div class="form-group"><!-- Display Name -->
<div class="row">
<div class="col-md-6 col-sm-6 col-xs-6 left">
<div class="error form-hint"
data-ng-show="registerForm.firstname.$dirty && registerForm.firstname.$error.required"
data-ng-cloak>{{"This field is required."}}
</div>
<input type="text" class="form-control" name="firstname" placeholder="First name"
data-ng-class="(registerForm.firstname.$dirty && registerForm.firstname.$invalid) ? 'error' : ''"
data-ng-required="true" data-ng-model="firstName">
</div>
<div class="col-md-6 col-sm-6 col-xs-6 right">
<div class="error form-hint"
data-ng-show="registerForm.lastname.$dirty && registerForm.lastname.$error.required"
data-ng-cloak>{{"This field is required."}}
</div>
<input type="text" class="form-control" name="lastname" placeholder="Last name"
data-ng-class="(registerForm.lastname.$dirty && registerForm.lastname.$invalid) ? 'error' : ''"
data-ng-required="true" data-ng-model="lastName">
</div>
</div>
</div>
</div>
</div>
<div class="form-group">
<div class="error form-hint"
data-ng-show="registerForm.username.$dirty && registerForm.username.$error.required"
data-ng-cloak>{{"This field is required."}}
</div>
<input type="text" class="form-control" id="userid" name="username" placeholder="User name"
data-ng-class="(registerForm.username.$dirty && registerForm.username.$invalid) ? 'error' : ''"
data-ng-required="true" data-ng-model="username">
</div>
<div class="form-group">
<div class="error form-hint"
data-ng-show="registerForm.email.$dirty && registerForm.email.$error.required"
data-ng-cloak>{{"You can't leave this empty."}}
</div>
<div class="error form-hint"
data-ng-show="registerForm.email.$dirty && registerForm.email.$error.email"
data-ng-cloak>{{"The email address you provided isn't valid"}}</div>
<input type="email" class="form-control" id="emailid" name="email" placeholder="Email address"
data-ng-class="(registerForm.email.$dirty && registerForm.email.$invalid) ? 'error' : ''"
data-ng-required="true" data-ng-model="email77">
</div>
<div class="form-group">
<div class="form-hint">
To conform with our Strong Password policy,
Use at least one letter, one numeral, one special character, and seven characters.
</div>
<input type="text" class="form-control" data-ok-password-directive
id="password" name="password" placeholder="Password" data-ng-required="true"
data-ng-class="(registerForm.password.$dirty && registerForm.confirm.$dirty
&& registerForm.confirm.$valid &&
( registerForm.password.$viewValue != registerForm.confirm.$viewValue ) ) ? 'error' : ''"
data-ng-model="passwordModel">
<div class="label password-count"
data-ng-class="passwordModel.length > 7 ? 'label-success' : 'label-danger'"
data-ng-cloak>{{ passwordModel | passwordCountFilter }}</div>
<div class="strength-meter">
<div class="strength-meter-fill" data-strength="{{myModulePasswordMeter}}"></div>
</div>
</div>
<div class="form-group">
<div class="error form-hint"
data-ng-show="registerForm.confirm.$dirty && !registerForm.confirm.$empty && registerForm.confirm.$error.required"
data-ng-cloak>{{"You can't leave this empty."}}
</div>
<div class="error form-hint"
data-ng-show="registerForm.confirm.$dirty && registerForm.confirm.$invalid && !registerForm.confirm.$error.required"
data-ng-cloak>{{"These passwords don't match. Try again?"}}</div>
<div class="error form-hint" data-ng-show="
( registerForm.confirm.$dirty && registerForm.confirm.$valid && !registerForm.confirm.$invalid) &&
( registerForm.password.$modelValue != registerForm.confirm.$modelValue )" data-ng-cloak>
{{'Password mismatch'}}
</div>
<!-- Enter to Confirm password | Enter for Password confirmation -->
<input type="text" class="form-control" id="confirmedID" name="confirm"
placeholder="Password confirmation"
data-ng-required="true" data-ng-model="confirm77"
data-ng-class="(registerForm.confirm.$dirty &&
( registerForm.confirm.$invalid ||
( registerForm.password.$modelValue != registerForm.confirm.$modelValue ) ) ) ? 'error' : ''"
data-compare-to="registerForm.password" >
</div>
<button id="siginButton" type="submit" class="btn" data-ng-disabled="registerForm.$invalid">Create an account</button>
</form>
</div>
</div>
</div>
</body>
Script Code:
(function() {
var loginModule = angular.module('loginModule', []);
loginModule.constant('USERCONSTANTS', (function() {
return {
PASSWORD_LENGTH: 7
}
})());
loginModule.controller('registerController', ['$scope','$http', '$window', '$location', registerControllerFun]);
function registerControllerFun($scope, $http, $window, $location) {
console.log(' registerControllerFun...');
}
loginModule.factory('myfactory', [function() {
return {
score: function() {
//console.log('arguments List : ', arguments);
var score = 0, value = arguments[0], passwordLength = arguments[1];
var containsLetter = /[a-zA-Z]/.test(value), containsDigit = /\d/.test(value), containsSpecial = /[^a-zA-Z\d]/.test(value);
var containsAll = containsLetter && containsDigit && containsSpecial;
console.log(" containsLetter - ", containsLetter,
" : containsDigit - ", containsDigit,
" : containsSpecial - ", containsSpecial);
if( value.length == 0 ) {
score = 0;
} else {
if( containsAll ) {
score += 3;
} else {
if( containsLetter ) score += 1;
if( containsDigit ) score += 1;
if( containsSpecial ) score += 1;
}
if(value.length >= passwordLength ) score += 1;
}
/*console.log('Factory Arguments : ', value, " « Score : ", score);*/
return score;
}
};
}]);
loginModule.directive('okPasswordDirective', ['myfactory', 'USERCONSTANTS', function(myfactory, USERCONSTANTS) {
return {
restrict: 'AC',
// use the NgModelController
require: 'ngModel',
// add the NgModelController as a dependency to your link function
link: function($scope, $element, $attrs, ngPasswordModel) {
console.log('Directive - USERCONSTANTS.PASSWORD_LENGTH : ', USERCONSTANTS.PASSWORD_LENGTH);
$element.on('blur change keydown', function( evt ) {
$scope.$evalAsync(function($scope) {
var pwd = $scope.password = $element.val();
$scope.myModulePasswordMeter = pwd ? (pwd.length > USERCONSTANTS.PASSWORD_LENGTH
&& myfactory.score(pwd, USERCONSTANTS.PASSWORD_LENGTH) || 0) : null;
ngPasswordModel.$setValidity('okPasswordController', $scope.myModulePasswordMeter > 3);
});
if( ngPasswordModel.$valid ) {
$scope.passwordVal = ngPasswordModel.$viewValue;
console.log('Updated Val : ', $scope.passwordVal);
$scope.updatePass();
}
});
}
};
}]);
loginModule.filter('passwordCountFilter', [ function() {
var passwordLengthDefault = 7;
return function( passwordModelVal ) {
passwordModelVal = angular.isString(passwordModelVal) ? passwordModelVal : '';
var retrunVal = passwordModelVal &&
(passwordModelVal.length > passwordLengthDefault ? passwordLengthDefault + '+' : passwordModelVal.length);
return retrunVal;
};
} ]);
var compareTo = function() {
return {
require: "ngModel",
// directive defines an isolate scope property (using the = mode) two-way data-binding
scope: {
passwordEleWatcher: "=compareTo"
},
link: function(scope, element, attributes, ngModel) {
console.log('Confirm Password Link Function call.');
var pswd = scope.passwordEleWatcher;
ngModel.$validators.compareTo = function( compareTo_ModelValue ) {
//console.log('scope:',scope);
if( (pswd != 'undefined' && pswd.$$rawModelValue != 'undefined') && (pswd.$valid && pswd.$touched) ) {
var pswdModelValue = pswd.$modelValue;
var isVlauesEqual = ngModel.$viewValue == pswdModelValue;
return isVlauesEqual;
} else {
console.log('Please enter valid password, before conforming the password.');
return false;
}
};
scope.$watch("passwordEleWatcher", function() {
console.log('$watch « Confirm-Password Element Watcher.')
ngModel.$validate();
});
scope.$parent.updatePass = function() {
console.log('$watch « Password Element Watcher.')
console.log('Pswd: ',scope.$parent.passwordVal, '\t Cnfirm:', ngModel.$modelValue);
//scope.registerForm.confirm.$invalid = true;
}
},
};
};
loginModule.directive("compareTo", compareTo);
})(window.angular);
Any help will be appreciated.
CSS classes Observed:
ng-pristine ng-untouched ng-empty ng-invalid ng-invalid-required form-control ng-isolate-scope ng-invalid-compare-to
ng-pristine ng-touched ng-empty ng-invalid ng-invalid-required form-control ng-isolate-scope ng-invalid-compare-to
ng-dirty ng-valid-parse ng-touched ng-not-empty ng-invalid ng-valid-required error form-control ng-isolate-scope ng-invalid-compare-to
ng-dirty ng-valid-parse ng-touched ng-empty ng-invalid ng-valid-required error form-control ng-isolate-scope ng-invalid-compare-to
ng-dirty ng-valid-parse ng-touched ng-not-empty ng-valid ng-valid-required form-control ng-isolate-scope ng-valid-compare-to
I just want to change css value from ng-valid to ng-invalid
Just added expression [To evaluate equality of password and conformation password] to the ng-disabled- Directive of a Button.
Code « Updated Fiddle
<button id="siginButton" type="submit" class="btn" data-ng-disabled="registerForm.$invalid">
Create an account
</button>
<!-- Changed to -->
<button id="siginButton" type="submit" class="btn"
data-ng-disabled="registerForm.$invalid
|| ( registerForm.confirm.$dirty && registerForm.confirm.$valid && !registerForm.confirm.$invalid )
&& ( registerForm.password.$modelValue != registerForm.confirm.$modelValue )">
Create an account
</button>
Confirm Password field with validation messages.
You can't leave this empty.
Confirm password with our Strong Password Policy.
These passwords don't match. Try again?
Solutions:
Disable Conformation Password field when the password field is invalid.
Updated Fiddle
User ng-pattern attribute to confirm. Updated Fiddle
Example:
<form name="registerForm" role="form" data-ng-submit="formSubmit()">
Password:<input type="password" name="password" ng-model="password77">
ConfirmPassword:<input type="password" name="confirm" ng-model="confirm77" ng-pattern="emailReg">
<div class="error form-hint" ng-messages="registerForm.confirm.$error" data-ng-show="registerForm.confirm.$dirty">
<p ng-show="registerForm.confirm.$error.required" ng-message="required">{{"You can't leave this empty."}}</p>
<p ng-show="!(registerForm.confirm.$error.pattern && registerForm.confirm.$error.required) && registerForm.password.$invalid && !registerForm.confirm.$invalid" ng-message="pattern">{{"Confirm Password with our strong password policy!"}}</p>
<p ng-show="registerForm.confirm.$invalid && !registerForm.confirm.$error.required && registerForm.confirm.$error.pattern" ng-message="">{{"These passwords don't match. Try again?"}}</p>
</div>
</form>

Why does the $asyncValidators in angularjs returns a promise but got undefined

So i'm new to the whole web thing and today i discover about $asyncValidators.
So after a lot of trying i get stuck with this example.
username.validator
(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) {
console.log("start");
console.log(viewValue);
console.log($http.post('/email', viewValue));
$http.post('/email',viewValue).then(function(response) {
console.log("Check if email is valid in directive")
console.log(response.data)
return response.data == true ? $q.reject(response.data.errorMessage) : true;
});
};
}
};
}
}());
register.html
<div class="container" ng-controller="RegisterController as vm">
<div class="col-md-6 col-md-offset-3">
<h2>Register</h2>
<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 class="form-group" ng-class="{ 'has-error': form.email.$dirty && form.email.$error.required }">
<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 ng-messages="form.email.$error">
<div ng-message="emailNotUsed">User with this email already exists.</div>
</div>
</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>
And now the where it got weird this is the output in the console
So why does this gives an error while i got the promise value? Any idea how to proceed
Asynchronous validators expect promise to be returned, you must therefore modify your validation function to return the result of $http call like this:
ngModel.$asyncValidators.emailNotUsed = function(modelValue, viewValue) {
return $http.post('/email',viewValue).then(function(response) {
return response.data == true ? $q.reject(response.data.errorMessage) : true;
});
};

How to call custom directive on form submit

I have a custom directive which works when I once change input value but when I submit form without changing input field value directive does not display error message.
html code:
<form name="myform" role="form" class="form-horizontal" method="post" novalidate>
<div class="form-group">
<label class="control-label col-sm-3" for="firstName">First name :</label>
<div class="col-sm-9">
<input name='firstName' class="form-control" type='text' required ng-model='name' string>
</div>
</div>
<div class="form-group">
<input type="submit" value="Submit" class="btn btn-success" />
</div>
</form>
directive :
validationModule.directive('string', function () {
return {
restrict: 'A',
require: 'ngModel',
link: function (scope, element, attr, ctrl) {
function validationError(value) {
if (value.length < 1) {
ctrl.$setValidity('required', false);
//showPopOver(element, "Required field");
errorValidation(element, "Required field");
// $(element).popover('show');
}
if (/[a-zA-Z]/.test(value)) {
ctrl.$setValidity('invalid', true);
// $(element).popover('destroy');
successValidation(element);
}
if (/[0-9]/.test(value)) {
ctrl.$setValidity('invalid', false)
errorValidation(element, "number not allowed");
// showPopOver(element, "number not allowed");
// $(element).popover('show');
}
return value;
}
ctrl.$parsers.push(validationError);
}
};
});
How can I call directive to perform validation on submit event ?
I don't know which version of angular you are using, but since 1.3 validators are not hacked into parsers. See $validators in https://docs.angularjs.org/api/ng/type/ngModel.NgModelController
Also using such generic names for directives is discouraged due to possible name collisions. Use some prefix eg myString

AngularJS watch not being triggered

I'm having a problem with AngularJs. I have created a directive that $watch the model and it takes some action based on the model's current status. However, although during debugging I can see that the $watch is set, it is only being triggered after the model get valid at least once and I don't know why that is happening. Debugging it doesn't even gets into the $watch function when something is typed.
The code is below:
Directive:
(function() {
'use strict';
var app = angular.module('app');
app.directive('tooltipValidation', function () {
return {
restrict: 'A',
require: 'ngModel',
link: function (scope, element, attrs, ngModel) {
var tooltip = $(element).qtip({
content: {
text: element.next('div')
},
show: false,
hide: true
}).qtip('api');
scope.$watch(attrs.ngModel, function() {
if (ngModel.$invalid && ngModel.$dirty) {
tooltip.show();
} else {
tooltip.hide();
}
});
}
};
});
})()
HTML:
<div class="form-address clearfix" ng-show="isNewShippingAddress" ng-form="newShippingAddressForm">
<h3>Include new shipping address:</h3>
<div class="novo-endereco clearfix" id="newAddress">
<div class="required address apelido">
<label for="newShippingAddressAlias">Alias</label>
<input id="newShippingAddressAlias" name="newShippingAddressAlias" type="text" tooltip-validation ng-model="newShippingAddress.Alias" required ng-maxlength="32" />
<div data-ng-show="newShippingAddressForm.newShippingAddressAlias.$dirty && newShippingAddressForm.newShippingAddressAlias.$invalid">
<p data-ng-show="newShippingAddressForm.newShippingAddressAlias.$error.required">obligatory</p>
<p data-ng-show="newShippingAddressForm.newShippingAddressAlias.$error.maxlength">max 32 char</p>
</div>
</div>
<div class="required endereco">
<label for="newShippingAddressStreet">Street</label>
<input id="newShippingAddressStreet" name="newShippingAddressStreet" type="text" tooltip-validation ng-model="newShippingAddress.Street" required ng-maxlength="256" />
<div data-ng-show="newShippingAddressForm.newShippingAddressStreet.$dirty && newShippingAddressForm.newShippingAddressStreet.$invalid">
<p data-ng-show="newShippingAddressForm.newShippingAddressStreet.$error.required">obligatory</p>
<p data-ng-show="newShippingAddressForm.newShippingAddressStreet.$error.maxlength">max 256 char</p>
</div>
</div>
<div class="required cep">
<label for="newShippingAddressZipCode">ZipCode</label>
<input id="newShippingAddressZipCode" name="newShippingAddressZipCode" type="text" tooltip-validation ng-model="newShippingAddress.ZipCode" required ng-pattern="/^[0-9]{8}$/" />
<div data-ng-show="newShippingAddressForm.newShippingAddressZipCode.$dirty && newShippingAddressForm.newShippingAddressZipCode.$invalid">
<p data-ng-show="newShippingAddressForm.newShippingAddressZipCode.$error.required">obligatory</p>
<p data-ng-show="newShippingAddressForm.newShippingAddressZipCode.$error.pattern">8 digits</p>
</div>
</div>
<input type="submit" class="button grey" value="Save new address" data-ng-click="saveShippingAddress()" ng-disabled="newShippingAddressForm.$invalid" />
</div>
</div>
Regards,
dimello
Try:
scope.$watch(function(){
return ngModel.$viewValue; //Watch for view value (the value in your input)
}, function() {
if (ngModel.$invalid && ngModel.$dirty) {
tooltip.show();
} else {
tooltip.hide();
}
});
DEMO
Explanation:
When you type an invalid value into the input with ng-model, the underlying model is not updated, causing your scope.$watch(attrs.ngModel not being fired because you're watching for changes in the model. If you need to fire the function every time the input changes no matter it's valid or not, try the above solution.

show validation error messages on submit in angularjs

I have a form which need to show validation error messages if clicked submit.
Here is a working plunker
<form name="frmRegister" ng-submit="register();" novalidate>
<div>
<input placeholder="First Name" name="first_name" type="text" ng-model="user.firstName" required />
<span ng-show="frmRegister.first_name.$dirty && frmRegister.first_name.$error.required">First Name is required</span>
</div>
<div>
<input placeholder="Last Name" name="last_name" type="text" ng-model="user.lastName" required />
<span ng-show="frmRegister.last_name.$dirty && frmRegister.last_name.$error.required">Last Name is required</span>
</div>
<div>
<input placeholder="Email" name="email" type="email" ng-model="user.email" required />
<span ng-show="frmRegister.email.$dirty && frmRegister.email.$error.required">Email is required.</span>
<span ng-show="frmRegister.email.$dirty && frmRegister.email.$error.email">Invalid Email address.</span>
</div>
<input type="submit" value="Save" />
<span ng-show="registered">YOU ARE NOW REGISTERED USER</span>
</form>
Validation works normally when user start making changes. But it doesn't show any error messages If clicked submit without entering anything.
Any thought of achieving this?. Or in other way how can I make each input field $dirty when clicks the Submit button
I found this fiddle http://jsfiddle.net/thomporter/ANxmv/2/ which does a nifty trick to cause control validation.
Basically it declares a scope member submitted and sets it true when you click submit. The model error binding use this extra expression to show the error message like
submitted && form.email.$error.required
UPDATE
As pointed out in #Hafez's comment (give him some upvotes!), the Angular 1.3+ solution is simply:
form.$submitted && form.email.$error.required
Since I'm using Bootstrap 3, I use a directive:
(see plunkr)
var ValidSubmit = ['$parse', function ($parse) {
return {
compile: function compile(tElement, tAttrs, transclude) {
return {
post: function postLink(scope, element, iAttrs, controller) {
var form = element.controller('form');
form.$submitted = false;
var fn = $parse(iAttrs.validSubmit);
element.on('submit', function(event) {
scope.$apply(function() {
element.addClass('ng-submitted');
form.$submitted = true;
if(form.$valid) {
fn(scope, {$event:event});
}
});
});
scope.$watch(function() { return form.$valid}, function(isValid) {
if(form.$submitted == false) return;
if(isValid) {
element.removeClass('has-error').addClass('has-success');
} else {
element.removeClass('has-success');
element.addClass('has-error');
}
});
}
}
}
}
}]
app.directive('validSubmit', ValidSubmit);
and then in my HTML:
<form class="form-horizontal" role="form" name="form" novalidate valid-submit="connect()">
<div class="form-group">
<div class="input-group col col-sm-11 col-sm-offset-1">
<span class="input-group-addon input-large"><i class="glyphicon glyphicon-envelope"></i></span>
<input class="input-large form-control" type="email" id="email" placeholder="Email" name="email" ng-model="email" required="required">
</div>
<p class="col-sm-offset-3 help-block error" ng-show="form.$submitted && form.email.$error.required">please enter your email</p>
<p class="col-sm-offset-3 help-block error" ng-show="form.$submitted && form.email.$error.email">please enter a valid email</p>
</div>
</form>
UPDATED
In my latest project, I use Ionic so I have the following, which automatically puts .valid or .invalid on the input-item's:
.directive('input', ['$timeout', function ($timeout) {
function findParent(element, selector) {
selector = selector || 'item';
var parent = element.parent();
while (parent && parent.length) {
parent = angular.element(parent);
if (parent.hasClass(selector)) {
break;
}
parent = parent && parent.parent && parent.parent();
}
return parent;
}
return {
restrict: 'E',
require: ['?^ngModel', '^form'],
priority: 1,
link: function (scope, element, attrs, ctrls) {
var ngModelCtrl = ctrls[0];
var form = ctrls[1];
if (!ngModelCtrl || form.$name !== 'form' || attrs.type === 'radio' || attrs.type === 'checkbox') {
return;
}
function setValidClass() {
var parent = findParent(element);
if (parent && parent.toggleClass) {
parent.addClass('validated');
parent.toggleClass('valid', ngModelCtrl.$valid && (ngModelCtrl.$dirty || form.$submitted));
parent.toggleClass('invalid', ngModelCtrl.$invalid && (ngModelCtrl.$dirty || form.$submitted));
$timeout(angular.noop);
}
}
scope.$watch(function () {
return form.$submitted;
}, function (b, a) {
setValidClass();
});
var before = void 0;
var update = function () {
before = element.val().trim();
ngModelCtrl.$setViewValue(before);
ngModelCtrl.$render();
setValidClass();
};
element
.on('focus', function (e) {
if (ngModelCtrl.$pristine) {
element.removeClass('$blurred');
}
})
.on('blur', function (e) {
if (ngModelCtrl.$dirty) {
setValidClass();
element.addClass('$blurred');
}
}).on('change', function (e) {
if (form.$submitted || element.hasClass('$blurred')) {
setValidClass();
}
}).on('paste', function (e) {
if (form.$submitted || element.hasClass('$blurred')) {
setValidClass();
}
})
;
}
};
}])
and then in the HTML:
<form name='form' novalidate="novalidate" ng-submit="auth.signin(form, vm)">
<label class="item item-input item-floating-label">
<span class="input-label">Email</span>
<input type="email" placeholder="Email" ng-model="vm.email" autofocus="true" required
>
</label>
<button ng-if="!posting" type="submit" class="item button-block item-balanced item-icon-right call-to-action">Login<i class="icon ion-chevron-right"></i>
</button>
and in the controller:
self.signin = function (form, data) {
if (!form.$valid) return;
Authentication.emailLogin(data)
//...
so, now, in the CSS, you can do stuff like:
.item.valid::before{
float: right;
font-family: "Ionicons";
font-style: normal;
font-weight: normal;
font-variant: normal;
text-transform: none;
text-rendering: auto;
line-height: 1;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
color: #66cc33;
margin-right: 8px;
font-size: 24px;
content: "\f122";
}
.item.invalid::before{
float: right;
font-family: "Ionicons";
font-style: normal;
font-weight: normal;
font-variant: normal;
text-transform: none;
text-rendering: auto;
line-height: 1;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
color: #ef4e3a;
margin-right: 8px;
font-size: 24px;
content: "\f12a";
/*
border-left: solid 2px #ef4e3a !important;
border-right: solid 2px #ef4e3a !important;
*/
}
MUCH SIMPLER!
I also had the same issue, I solved the problem by adding a ng-submit which sets the variable submitted to true.
<form name="form" ng-submit="submitted = true" novalidate>
<div>
<span ng-if="submitted && form.email.$error.email">invalid email address</span>
<span ng-if="submitted && form.email.$error.required">required</span>
<label>email</label>
<input type="email" name="email" ng-model="user.email" required>
</div>
<div>
<span ng-if="submitted && form.name.$error.required">required</span>
<label>name</label>
<input type="text" name="name" ng-model="user.name" required>
</div>
<button ng-click="form.$valid && save(user)">Save</button>
</form>
I like the idea of using $submitted, I think I've to upgrade Angular to 1.3 ;)
I can come up with 2 ways to achieve it.
The first one is to remove novalidate to enable the browser's validation.
Second, you can disable the save button when the form is not valid like this
<input ng-disabled="!frmRegister.$valid" type="submit" value="Save" />
Hope it helps.
There are two simple & elegant ways to do it.
Pure CSS:
After first form submission, despite the form validity, Angular will add a ng-submitted class to all form elements inside the form just submitted.
We can use .ng-submitted to controller our element via CSS.
if you want to display an error text only when user have submitted e.g.
.error { display: none }
.ng-submitted .error {
display: block;
}
Using a value from Scope:
After first form submission, despite the form validity, Angular will set [your form name].$submitted to true. Thus, we can use that value to control elements.
<div ng-show="yourFormName.$submitted">error message</div>
<form name="yourFormName"></form>
My solution with bootstrap 3
http://jsfiddle.net/rimian/epxrbzn9/
<form class="form" name="form" ng-app novalidate>
<div class="form-group">
<input name="first_name"
type="text"
class="form-control"
ng-model="first_name"
placeholder="First Name"
required />
</div>
<div class="form-group">
<input name="last_name"
type="text"
class="form-control"
ng-model="last_name"
placeholder="Last Name"
required />
</div>
<button
type="submit"
class="btn btn-primary btn-large"
ng-click="submitted=true">
Submit
</button>
<div ng-show="submitted && form.$invalid" class="alert alert-danger">
<div ng-show="form.first_name.$error.required">
First Name is Required
</div>
<div ng-show="form.last_name.$error.required">
Last Name is Required
</div>
</div>
</form>
You only need to check if the form is dirty and valid before submitting it. Checkout the following code.
<form name="frmRegister" data-ng-submit="frmRegister.$valid && frmRegister.$dirty ? register() : return false;" novalidate>
And also you can disable your submit button with the following change:
<input type="submit" value="Save" data-ng-disable="frmRegister.$invalid || !frmRegister.$dirty" />
This should help for your initial
http://jsfiddle.net/LRD5x/30/ A simple solution.
HTML
<form ng-submit="sendForm($event)" ng-class={submitted:submitted}>
JS
$scope.sendForm = function($event) {
$event.preventDefault()
$scope.submitted = true
};
CSS
.submitted input.ng-invalid:not(:focus) {
background-color: #FA787E;
}
input.ng-invalid ~ .alert{
display:none;
}
.submitted input.ng-invalid ~ .alert{
display:block;
}
I like the solution from realcrowd the best.
HTML:
<form role="form" id="form" name="form" autocomplete="off" novalidate rc-submit="signup()">
<div class="form-group" ng-class="{'has-error': rc.form.hasError(form.firstName)}">
<label for="firstName">Your First Name</label>
<input type="text" id="firstName" name="firstName" class="form-control input-sm" placeholder="First Name" ng-maxlength="40" required="required" ng-model="owner.name.first"/>
<div class="help-block" ng-show="rc.form.hasError(form.firstName)">{{rc.form.getErrMsg(form.firstName)}}</div>
</div>
</form>
javascript:
//define custom submit directive
var rcSubmitDirective = {
'rcSubmit': ['$parse', function ($parse) {
return {
restrict: 'A',
require: ['rcSubmit', '?form'],
controller: ['$scope', function ($scope) {
this.attempted = false;
var formController = null;
this.setAttempted = function() {
this.attempted = true;
};
this.setFormController = function(controller) {
formController = controller;
};
this.hasError = function (fieldModelController) {
if (!formController) return false;
if (fieldModelController) {
return fieldModelController.$invalid && this.attempted;
} else {
return formController && formController.$invalid && this.attempted;
}
};
this.getErrMsg=function(ctrl){
var e=ctrl.$error;
var errMsg;
if (e.required){
errMsg='Please enter a value';
}
return errMsg;
}
}],
compile: function(cElement, cAttributes, transclude) {
return {
pre: function(scope, formElement, attributes, controllers) {
var submitController = controllers[0];
var formController = (controllers.length > 1) ? controllers[1] : null;
submitController.setFormController(formController);
scope.rc = scope.rc || {};
scope.rc[attributes.name] = submitController;
},
post: function(scope, formElement, attributes, controllers) {
var submitController = controllers[0];
var formController = (controllers.length > 1) ? controllers[1] : null;
var fn = $parse(attributes.rcSubmit);
formElement.bind('submit', function (event) {
submitController.setAttempted();
if (!scope.$$phase) scope.$apply();
if (!formController.$valid) return false;
scope.$apply(function() {
fn(scope, {$event:event});
});
});
}
};
}
};
}]
};
app.directive(rcSubmitDirective);
A complete solution to the validate form with angularjs.
HTML is as follows.
<div ng-app="areaApp" ng-controller="addCtrler">
<form class="form-horizontal" name="fareainfo">
<div class="form-group">
<label for="input-areaname" class="col-sm-2 control-label">Area Name : </label>
<div class="col-sm-4">
<input type="text" class="form-control" name="name" id="input-areaname" ng-model="Area.Name" placeholder="" required>
<span class="text-danger" ng-show="(fareainfo.$submitted || fareainfo.name.$dirty) && fareainfo.name.$error.required"> Field is required</span>
</div>
</div>
<div class="col-sm-12">
<button type="button" class="btn btn-primary pull-right" ng-click="submitAreaInfo()">Submit</button>
</div>
</form>
</div>
AngularJS App and Controller is as follows
var areaApp = angular.module('areaApp', []);
areaApp.controller('addCtrler', function ($scope) {
$scope.submitAreaInfo = function () {
if ($scope.fareainfo.$valid) {
//after Form is Valid
} else {
$scope.fareainfo.$setSubmitted();
}
};
});
Important Code Segments
ng-app="areaApp" ng-controller="addCtrler"
Defines the angular app and controller
ng-show="(fareainfo.$submitted || fareainfo.name.$dirty) && fareainfo.name.$error.required"
Above condition ensure that whenever a user first sees the form there's no any validation error on the screen and after a user does changes to the form it ensure that validation message show on the screen. .name. is the name attribute of the input element.
$scope.fareainfo.$valid
Above code, segment check whether the form is valid whenever a user submits the form.
$scope.fareainfo.$setSubmitted();
Above code, segment ensures that all validation messages are displayed on the screen whenever a user submits the form without doing anything.
// This worked for me.
<form name="myForm" class="css-form" novalidate ng-submit="Save(myForm.$invalid)">
<input type="text" name="uName" ng-model="User.Name" required/>
<span ng-show="User.submitted && myForm.uName.$error.required">Name is required.</span>
<input ng-click="User.submitted=true" ng-disabled="User.submitted && tForm.$invalid" type="submit" value="Save" />
</form>
// in controller
$scope.Save(invalid)
{
if(invalid) return;
// save form
}
G45,
I faced same issue , i have created one directive , please check below hope it may be helpful
Directive :
app.directive('formSubmitValidation', function () {
return {
require: 'form',
compile: function (tElem, tAttr) {
tElem.data('augmented', true);
return function (scope, elem, attr, form) {
elem.on('submit', function ($event) {
scope.$broadcast('form:submit', form);
if (!form.$valid) {
$event.preventDefault();
}
scope.$apply(function () {
scope.submitted = true;
});
});
}
}
};
})
HTML :
<form name="loginForm" class="c-form-login" action="" method="POST" novalidate="novalidate" form-submit-validation="">
<div class="form-group">
<input type="email" class="form-control c-square c-theme input-lg" placeholder="Email" ng-model="_username" name="_username" required>
<span class="glyphicon glyphicon-user form-control-feedback c-font-grey"></span>
<span ng-show="submitted || loginForm._username.$dirty && loginForm._username.$invalid">
<span ng-show="loginForm._username.$invalid" class="error">Please enter a valid email.</span>
</span>
</div>
<button type="submit" class="pull-right btn btn-lg c-theme-btn c-btn-square c-btn-uppercase c-btn-bold">Login</button>
</form>
Try this code:
<INPUT TYPE="submit" VALUE="Save" onClick="validateTester()">
This funvtion will validate your result
function validateTester() {
var flag = true
var Tester = document.forms.Tester
if (Tester.line1.value!="JavaScript") {
alert("First box must say 'JavaScript'!")
flag = false
}
if (Tester.line2.value!="Kit") {
alert("Second box must say 'Kit'!")
flag = false
}
if (flag) {
alert("Form is valid! Submitting form...")
document.forms.Tester.submit()
}
}

Categories

Resources