EDIT:
I've added a JsFiddle so you can easily troubleshoot instead of having to set up the environment yourself. As you can see, validation is done on the Email field even before the blur event on the input element, which was triggered by the $scope.Email being changed. If you comment out the ng-show="!mainForm.validate()" on the <p> element, you'll see that the issue doesn't take place.
I am using the Angular implementation of jQuery Validate, and I am in need of the ability to check if a form is valid without showing the error messages. The standard solution I've seen online is to use jQuery Validate's checkForm() function, like this:
$('#myform').validate().checkForm()
However, the Angular wrapper I'm using doesn't currently implement the checkForm function. I have been trying to modify the source code to bring it in, and I'm afraid I'm in over my head. The code is small and simple enough that I'll paste it here:
(function (angular, $) {
angular.module('ngValidate', [])
.directive('ngValidate', function () {
return {
require: 'form',
restrict: 'A',
scope: {
ngValidate: '='
},
link: function (scope, element, attrs, form) {
var validator = element.validate(scope.ngValidate);
form.validate = function (options) {
var oldSettings = validator.settings;
validator.settings = $.extend(true, {}, validator.settings, options);
var valid = validator.form();
validator.settings = oldSettings; // Reset to old settings
return valid;
};
form.numberOfInvalids = function () {
return validator.numberOfInvalids();
};
//This is the part I've tried adding in.
//It runs, but still shows error messages when executed.
//form.checkForm = function() {
// return validator.checkForm();
//}
}
};
})
.provider('$validator', function () {
$.validator.setDefaults({
onsubmit: false // to prevent validating twice
});
return {
setDefaults: $.validator.setDefaults,
addMethod: $.validator.addMethod,
setDefaultMessages: function (messages) {
angular.extend($.validator.messages, messages);
},
format: $.validator.format,
$get: function () {
return {};
}
};
});
}(angular, jQuery));
I want to be able to use it to show or hide a message, like this:
<p class="alert alert-danger" ng-show="!mainForm.checkForm()">Please correct any errors above before saving.</p>
The reason I don't just use !mainForm.validate() is because that causes the error messages to be shown on elements before they are "blurred" away from, which is what I'm trying to avoid. Can anyone help me implement the checkForm() function into this angular directive?
You can add checkForm() function to the plugin as following.
(function (angular, $) {
angular.module('ngValidate', [])
.directive('ngValidate', function () {
return {
require: 'form',
restrict: 'A',
scope: {
ngValidate: '='
},
link: function (scope, element, attrs, form) {
var validator = element.validate(scope.ngValidate);
form.validate = function (options) {
var oldSettings = validator.settings;
validator.settings = $.extend(true, {}, validator.settings, options);
var valid = validator.form();
validator.settings = oldSettings; // Reset to old settings
return valid;
};
form.checkForm = function (options) {
var oldSettings = validator.settings;
validator.settings = $.extend(true, {}, validator.settings, options);
var valid = validator.checkForm();
validator.submitted = {};
validator.settings = oldSettings; // Reset to old settings
return valid;
};
form.numberOfInvalids = function () {
return validator.numberOfInvalids();
};
}
};
})
.provider('$validator', function () {
$.validator.setDefaults({
onsubmit: false // to prevent validating twice
});
return {
setDefaults: $.validator.setDefaults,
addMethod: $.validator.addMethod,
setDefaultMessages: function (messages) {
angular.extend($.validator.messages, messages);
},
format: $.validator.format,
$get: function () {
return {};
}
};
});
}(angular, jQuery));
Please find the updated jsFiddle here https://jsfiddle.net/b2k4p3aw/
Reference: Jquery Validation: Call Valid without displaying errors?
If I understand your question correctly, you want to be able to show an error message when the email adress is invalid and you decide you want to show the error message.
You can achieve this by setting the input type to email like this <input type=email>
Angular adds an property to the form $valid so you can check in your controller if the submitted text is valid. So we only have to access this variable in the controller and invert it. (Because we want to show the error when it is not valid)
$scope.onSubmit = function() {
// Decide here if you want to show the error message or not
$scope.mainForm.unvalidSubmit = !$scope.mainForm.$valid
}
I also added a submit button that uses browser validation on submit. This way the onSubmit function won't even get called and the browser will show an error. These methods don't require anything except angularjs.
You can check the updated JSFiddle here
Make sure to open your console to see when the onSubmit function gets called and what value gets send when you press the button.
You can use $touched, which is true as soon as the field is focused then blurred.
<p class="alert alert-danger" ng-show="mainForm.Email.$touched && !mainForm.validate()">Please correct any errors above before saving.</p>
you can achieve onblur event with ng-show="mainForm.Email.$invalid && mainForm.Email.$touched" to <p> tag
by default mainForm.Email.$touched is false, on blur it will change to true
for proper validation change the <input> tag type to email
you can add ng-keydown="mainForm.Email.$touched=false" if you don't want to show error message on editing the input tag
I didn't used angular-validate.js plugin
<div ng-app="PageModule" ng-controller="MainController" class="container"><br />
<form method="post" name="mainForm" ng-submit="OnSubmit(mainForm)" >
<label>Email:
<input type="email" name="Email" ng-keydown="mainForm.Email.$touched=false" ng-model="Email" class="email" />
</label><br />
<p class="alert alert-danger" ng-show="mainForm.Email.$invalid && mainForm.Email.$touched">Please correct any errors above before saving.</p>
<button type="submit">Submit</button>
</form>
</div>
Updated code : JSFiddle
AngularJs Form Validation
More info on Angular validation
Update 2
checkForm will return whether the form is valid or invalid
// added checForm, also adds valid and invalid to angular
form.checkForm = function (){
var valid = validator.form();
angular.forEach(validator.successList, function(value, key) {
scope.$parent[formName][value.name].$setValidity(value.name,true);
});
angular.forEach(validator.errorMap, function(value, key) {
scope.$parent[formName][key].$setValidity(key,false);
});
return valid
}
to hide default messages adding by jQuery validation plugin add below snippet, to $.validator.setDefaults
app.config(function ($validatorProvider) {
$validatorProvider.setDefaults({
errorPlacement: function(error,element) { // to hide default error messages
return true;
}
});
});
here is the modified plugin looks like
(function (angular, $) {
angular.module('ngValidate', [])
.directive('ngValidate', function () {
return {
require: 'form',
restrict: 'A',
scope: {
ngValidate: '='
},
link: function (scope, element, attrs, form) {
var validator = element.validate(scope.ngValidate);
var formName = validator.currentForm.name;
form.validate = function (options) {
var oldSettings = validator.settings;
validator.settings = $.extend(true, {}, validator.settings, options);
var valid = validator.form();
validator.settings = oldSettings; // Reset to old settings
return valid;
};
form.numberOfInvalids = function () {
return validator.numberOfInvalids();
};
// added checkForm
form.checkForm = function (){
var valid = validator.form();
angular.forEach(validator.successList, function(value, key) {
scope.$parent[formName][value.name].$setValidity(value.name,true);
});
angular.forEach(validator.errorMap, function(value, key) {
scope.$parent[formName][key].$setValidity(key,false);
});
return valid
}
}
};
})
.provider('$validator', function () {
$.validator.setDefaults({
onsubmit: false // to prevent validating twice
});
return {
setDefaults: $.validator.setDefaults,
addMethod: $.validator.addMethod,
setDefaultMessages: function (messages) {
angular.extend($.validator.messages, messages);
},
format: $.validator.format,
$get: function () {
return {};
}
};
});
}(angular, jQuery));
controller
app.controller("MainController", function($scope) {
$scope.Email = "";
$scope.url = "";
$scope.isFormInValid = false; // to hide validation messages
$scope.OnSubmit = function(form) {
// here you can determine
$scope.isFormInValid = !$scope.mainForm.checkForm();
return false;
}
})
need to have following on every input tag(example for email)
ng-show="isFormInValid && !mainForm.Email.$invalid "
if the form and email both are invalid the validation message shows up.
JSFiddle
try this code for validation this is the form
<form name="userForm" ng-submit="submitForm(userForm.$valid)" novalidate>
<div class="form-group">
<input type="text" ng-class="{ 'has-error' : userForm.name.$invalid && !userForm.name.$pristine }" ng-model="name" name="name" class="form-control" placeholder="{{ 'regName' | translate }}" required>
<p ng-show="userForm.name.$invalid && !userForm.name.$pristine" class="help-block">Your name is required.</p>
</div>
<div class="form-group">
<input type="tel" ng-class="{ 'has-error' : userForm.mob.$invalid && !userForm.mob.$pristine }" ng-model="mob" class="form-control" name="mob" ng-maxlength="11" ng-minlength="11" ng-pattern="/^\d+$/" placeholder="{{ 'regPhone' | translate }}" required>
<p ng-show="userForm.mob.$invalid && !userForm.mob.$pristine" class="help-block">Enter a valid number</p>
</div>
<div class="form-group">
<input type="email" ng-model="email" name="email" class="form-control" placeholder="{{ 'regEmail' | translate }}" required>
<p ng-show="userForm.email.$invalid && !userForm.email.$pristine" class="help-block">Enter a valid email.</p>
</div>
<div class="form-group">
<input type="password" ng-model="pass" name="pass" class="form-control" placeholder="{{ 'regPass' | translate }}" minlength="6" maxlength="16" required>
<p ng-show="userForm.pass.$invalid && !userForm.pass.$pristine" class="help-block"> Too short Min:6 Max:16</p>
<input type="password" ng-model="repass" class="form-control" ng-minlength="6" placeholder="{{ 'regConPass' | translate }}" ng-maxlength="16" required>
</div>
<button class="loginbtntwo" type="submit" id="regbtn2" ng-disabled="userForm.$dirty && userForm.$invalid" translate="signUp" ></button>
</form>
You will need to modify the Angular Validate Plugin a bit. Here is a working version of your code in JSFiddle. Note the updated plugin code as well as a pair of modifications to your original code.
Updated plugin code simply adds this to validator.SetDefaults parameter:
errorPlacement: function(error,element) { return true; } // to hide default error message
Then we use a scope variable to hide/show the custom error message:
$scope.OnSubmit = function(form) {
if (form.$dirty) {
if (form.validate()) {
//form submittal code
} else {
$scope.FormInvalid = true;
}
}
something similar may have been answered (ng-pattern + ng-change) but all responses were unable to fix this issue.
I have two imbricated directives for creating a form input, a parent directive to control name, label, validator etc. and a child directive to set pattern and input type specific stuff.
However, when setting a pattern, the value on my model is set to undefined when ng-pattern return false.
Directives:
<input-wrapper ng-model="vm.customer.phone" name="phone" label="Phone number">
<input-text type="tel"></input-text>
</input-wrapper>
Generated HTML:
<label for="phone">Phone number:</label>
<input type="text" name="phone"
ng-model="value"
ng-model-options="{ updateOn: \'blur\' }"
ng-change="onChange()"
ng-pattern="/^[\+]?[(]?[0-9]{3}[)]?[-\s\.]?[0-9]{3}[-\s\.]?[0-9]{4,6}$/">
JS:
angular.module('components', [])
.directive('inputWrapper', function() {
return {
restrict: 'E',
require: 'ngModel',
scope: true,
link: function (scope, element, attrs, ngModel) {
scope.name = attrs.name;
scope.label = attrs.label;
scope.onChange = function () {
ngModel.$setViewValue(scope.value);
};
ngModel.$render = function () {
scope.value = ngModel.$modelValue;
};
}
}
})
.directive('inputText', function() {
return {
restrict: 'E',
template: '<label for="{{name}}">{{label}}:</label><input type="text" name="{{name}}" ng-model="value" ng-model-options="{ updateOn: \'blur\' }" ng-change="onChange()" ng-pattern="pattern">',
link: function (scope, element, attrs) {
if (attrs.type === 'tel') {
scope.pattern = /^[\+]?[(]?[0-9]{3}[)]?[-\s\.]?[0-9]{3}[-\s\.]?[0-9]{4,6}$/;
}
}
}
});
angular.module('app',['components'])
.controller('ctrl',function($scope){
var vm = this;
vm.customer = {
phone: '010203040506'
};
});
What am I doing wrong ?
Codepen for use case: https://codepen.io/Yosky/pen/yVrmvw
By default in angular if a validator fail, undefined value assigned to ng-model, You can change this setting as follow :
<div ng-model-options="{ allowInvalid: true}">
read here for detail docs
I had some requirements that meant that I really really didn't want ng-model to write out undefined to the scope when validation was invalid, and I didn't want the invalid value either, so allowInvalid didn't help. In stead I just wanted ng-model do not write anything, but I couldn't find any option for this.
So I couldn't see any way forward except for doing some monkey patching of the ng-model controller.
So first I required ngModel in the component I was building require: { model: 'ngModel' } and then I did this in the $onInit hook:
const writeModelToScope = this.model.$$writeModelToScope;
const _this = this;
this.model.$$writeModelToScope = function() {
const allowInvalid = _this.model.$options.getOption('allowInvalid');
if (!allowInvalid && _this.model.$invalid) {
return;
}
writeModelToScope.bind(this)();
};
I also didn't want to take in a new model value while the value was invalid and the component had focus, so I did:
const setModelValue = this.model.$$setModelValue;
this.model.$$setModelValue = function(modelValue) {
_this.lastModelValue = modelValue;
if (_this.model.$invalid) {
return;
}
if (_this.hasFocus) {
return;
}
setModelValue.bind(this)(modelValue);
};
element.on('focus', () => {
this.hasFocus = true;
});
element.on('blur', (event) => {
this.hasFocus = false;
const allowInvalid = this.model.$options.getOption('allowInvalid');
if (!allowInvalid && this.model.$invalid) {
this.value = this.lastModelValue;
}
event.preventDefault();
});
Feel free to judge me, just know that I already feel dirty.
I'm facing an issue which I can't seem to solve.
I have several inputs with each a directive to validate the input value, like this:
<div class="row form-group">
<div class="col-sm-6">last name</div>
<div class="col-sm-6">
<div class="input-group" ng-class="{'has-error': form.lastname.$invalid && (form.lastname.$touched || form.$submitted)}">
<input type="text" name="lastname" class="form-control"
model-blur
validator-lastname
ng-trim="true"
ng-model="fields.lastname.value"
ng-maxlength="fields.lastname.validation.maxLength">
<input-group-addon class="input-group-addon"
iga-char=""
iga-form="form"
iga-field="form.lastname"
iga-if-touched="true">
</input-group-addon>
</div>
<form-message-list fml-form="form"
fml-field="form.lastname"
fml-label="Last name"
fml-fieldData="fields.lastname">
</form-message-list>
</div>
</div>
This field required the following pattern: /^[\'a-zA-Z_]+( [\'a-zA-Z_]+)*$/
My issue is this:
When I add an invalid value to my input, like this: / , my invalid message remains and ng-invalid-pattern remains on my field.
When I add this pattern to my field like this: ng-pattern="/^[\'a-zA-Z_]+( [\'a-zA-Z_]+)*$/" I don't have any issues. But when I try to validate via my directive validator-lastname it only checks one time. When I fill the input with an invalid value and then change it to empty, which is allowed, the ng-invalid-pattern error remains.
This is my directive:
angular.module('app')
.directive('validatorLastname', validatorLastname);
/* #ngInject */
function validatorLastname() {
var directive = {
require: 'ngModel',
link: link
};
return directive;
function link(scope, element, attrs, modelCtrl) {
var valid = false;
var formatter = function (inputValue) {
if (inputValue) {
var res = inputValue.match(/^[\'a-zA-Z_]+( [\'a-zA-Z_]+)*$/);
if (res && res.length > 0) {
valid = true;
}
modelCtrl.$setValidity('pattern', valid);
valid = false;
}
return inputValue;
};
modelCtrl.$parsers.push(formatter);
if (scope[attrs.ngModel] && scope[attrs.ngModel] !== '') {
formatter(scope[attrs.ngModel]);
}
}
}
I made a JSFiddle to reproduce the problem: http://jsfiddle.net/sZZEt/537/
I hope someone can point me in the right direction.
Thanks in advance.
You should update your directive code to make everything work fine.
angular.module('app')
.directive('validatorLastname', validatorLastname);
/* #ngInject */
function validatorLastname() {
var directive = {
require: 'ngModel',
link: link
};
return directive;
function link(scope, element, attrs, modelCtrl) {
var valid = false;
var formatter = function (inputValue) {
if (inputValue) {
var res = inputValue.match(/^[\'a-zA-Z_]+( [\'a-zA-Z_]+)*$/);
if (res && res.length > 0) {
valid = true;
}
modelCtrl.$setValidity('pattern', valid);
valid = false;
}else{
modelCtrl.$setValidity('pattern', true);
}
return inputValue;
};
modelCtrl.$parsers.push(formatter);
if (scope[attrs.ngModel] && scope[attrs.ngModel] !== '') {
formatter(scope[attrs.ngModel]);
}
}
}
I have created a plunk for your problem...
It is because if inputValue is null then your $setValidity method will not invoke and could not perform validation again. You should set pattern validity to true inside else part. if you want to make field valid for no-input.
You can now refer to updated plunk https://plnkr.co/edit/N3DrsB?p=preview
I am trying to create a directive that will skip validation if a field is disabled.
I am using this approach :
implementing a directive to exclude a hidden input element from validation ($addControl issue)
My directive is :
dashboardApp.directive('shownValidation', function() {
return {
require: '^form',
restrict: 'A',
link: function(scope, element, attrs,form) {
var control;
scope.$watch(attrs.disabled,function(value){
if (!control){
control = form[element.attr("name")];
}
if (value == false){
form.$addControl(control);
angular.forEach(control.$error, function(validity, validationToken) {
form.$setValidity(validationToken, !validity, control);
});
} else {
console.log("Before remove control." + control.$name + " Form valid = " + form.$valid);
form.$removeControl(control);
console.log("After remove control." + control.$name + " Form valid = " + form.$valid);
}
});
}
};
});
In my app controller I have an watch to my $valid state of the form
$scope.$watch("userProfileForm.$valid", function(newValue) {
console.log("Log in controller for userProfileForm.$valid= " + newValue);
});
My input declaration in jsp is:
<input type = "text" name = "title" ng-disabled = "PROFILE_DISABLED_FIELDS_TITLE" required shown-validation />
I am displaying in the page the valid state of the form in a div <div>{{userProfileForm.$valid}}</div> to check it because based on the $valid state I am disable / enable the save button.
Here are the logs when I am open the page:
profile-editor-controller.js:164 Log in controller for userProfileForm.$valid= true
pc-directives.js:460 Before remove control.title Form valid = false
pc-directives.js:462 After remove control.title Form valid = true
profile-editor-controller.js:164 Log in controller for userProfileForm.$valid= false
There are other input fields in the form that are having validators but I made sure that they are all valid for the purpose of example.
If I put a breakpoint in the controller after the page is fully loaded and the message on the console are printed,I can see that $scope.userProfileForm.$error.required[0].$name == "title"
but if I look on the field is not on the form anymore:
$scope.userProfileForm.title == undefined
Any ideas where I am wrong or where is the trick ?
Later Edit:
After I read some articles about $watch and $observe I found that these two functions are working different based on your angular version and made me try a different approach and I found a solution for my case:
app.directive('validIfDisabled', function() {
return {
require: 'ngModel',
restrict: 'A',
link: function(scope, element, attrs,model) {
var disabled=false;
function makeModelValid (model){
angular.forEach(model.$validators, function(validatorValue, validatorKey) {
model.$setValidity(validatorKey,true);
});
}
attrs.$observe( "disabled", function (value) {
disabled = value;
if(disabled){
makeModelValid(model);
}else{
model.$validate();
}
});
scope.$watch(function(){return model.$invalid;},function(){
if(disabled){
makeModelValid(model);
}
});
}
};
});
Hi i'm using an User Name validator in my project.But when I started writing some thing it's requesting for every characters after reach min length.
Here you can see in pic.
Here is my soruces;
Input parse in page:
<input type="text" id="regUserName" name="regUserName" required minlength="5" maxlength="15" class="form-control" placeholder="Kullanıcı Adı" data-ng-model="regUserName" username-validator />
And here validator in ValidationService.js:
angular.module('BlogAppModule').directive('usernameValidator', function ($http, $q) {
return {
require: 'ngModel',
link: function ($scope, element, attrs, ngModel) {
ngModel.$asyncValidators.usernameAvailable = function (username) {
return $http.get('/api/CheckUserName/' + username)
.then(function (response) {
var warning = document.getElementById("regUserName");
if (response.data != null) {
warning.style.backgroundColor = "red";
}
else {
warning.style.backgroundColor = "white";
}
})
}
}
};
});
Now here my some questions about this:
Will be a problem about this requests?(Like performance problem)
Can I set this validation like when I leave the textbox then check
username?If this is possible, what should I do?
When user write "." requesting don't work.How can I disable in
textinput special chars like : " . - , ! # " etc.
By default, changes will be written back to the model on every change.
Use ng-model-options="{ updateOn: 'blur' }" on the input element to update the binding when leaving the input field.
If you want to add client side validation as well, you can add a synchronous validator. $validators will be executed before $asyncValidatorss.
link: function ($scope, element, attrs, ngModel) {
ngModel.$asyncValidators.usernameAvailable = function (username) {
// your server side validation
};
ngModel.$validators.userNameOk = function(username) {
return username && username.indexOf('.') < 0;
};
}
http://plnkr.co/edit/Yd8C8Ut9VWPXEvDEMjFJ?p=preview