Date input validation using ng-change, AngularJS - javascript

I's using AngularJS and AngularJS bootstrap in my page. I have a date picker directive that looks like this:
<div class="form-group {{dateStatus.class}}">
<p class="input-group">
<input type="text" id="inpDate" class="form-control"
datepicker-popup="dd-MMMM-yyyy" ng-model="task.date"
is-open="datePickerStatus.isOpen" min-date="minDate"
datepicker-options="dateOptions" ng-required="true"
close-text="Close" placeholder="Due date"
ng-change="checkDateValidity()"
/>
<span class="input-group-btn">
<button type="button" class="btn btn-default"
ng-click="openDatePicker($event)"
>
<i class="glyphicon glyphicon-calendar"></i>
</button>
</span>
</p>
</div>
To validate the date input, in my controller I have the following function:
$scope.checkDateValidity = function(){
var date,
isValid,
taskDate;
taskDate = $scope.task.date;
date = new Date(taskDate);
isValid = !isNaN(date);
if(isValid) {
$scope.addButtonState.isOk = true;
$scope.dateStatus.class = '';
}
else{
$scope.addButtonState.isOk = false;
$scope.dateStatus.class = 'has-error';
}
}
everything works fine for checking if the date inserted is valid, but the problem is that when the date input is left blank(or changed from a valid state to blank)
I want it to be acceptable too, but since both empty input and invalid date are undefinedI don't know how to declare between the cases.
I also thought of reading the input text directly like this:
document.getElementById('inpDate').value
but the ng-change is fired when the value is changed and I'm left with the previous value which is useless now...
thanks for your time and response.

A much better way of validating is using a directive to add a Validation Rule.
.directive("validateDate", function() {
return {
require: 'ngModel',
link: function(scope, elm, attrs, ctrl) {
ctrl.$validators.validateDate = function(modelValue, viewValue) {
if(!isNaN(modelValue) || ctrl.$isEmpty(modelValue)){
return true;
}
return false;
};
}
};
})
then you just need to add validate-date to the input tag and the validation will mark the input as valid if it is !isNaN (when the date is a number OR is empty)

You can easily validate #inpDate value by binding validator callback to both change and keyup events, then when your callback triggered you can check the validity of your input.
$timeout(function(){
angular
.element(document.getElementById('inpDate'))
.bind('keyup change', function(){
var inputValue,
customDate,
isValid;
inputValue = this.value;
if(inputValue != ''){
customDate = new Date(inputValue);
isValid = !isNaN(customDate);
if(isValid){
console.log('Valid');
// do something
}
else{
console.log('Invalid');
// do something else
}
}
else{
console.log('Empty');
// do something else
}
});
}, 400);
Please make sure that your have injected $timeout in your controller.

If you want to validate like that, then you can use
if(document.getElementById('inpDate').value === "" ){
$scope.addButtonState.isOk = true;
$scope.dateStatus.class = '';
}
this at the beginning of the $scope.checkDateValidity function

Related

How to use the Angular jQuery Validate's checkForm() function

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;
}
}

JavaScript function return html object, how can I parse it?

I have an AngularJS (1.4) application and I'm trying to manipulate a input type="number" through a directive.
I have to use type="number" because with type="tel" on iOs the character "." does not appear in the keyboard and this make impossibile to insert decimals number.
The goal is to make the user insert maximum 3 digits before the "." and maximum 2 digits after. The number of dots must not exceed one. That's the format I want in my input field.
The problem is that if I pass I print the variable this.value in the directive, it doesn't contain any ".".
Here's the html code:
<input required type='number' limit-to-number="3" number-of-decimals="2" ng-required="true" ng-model="invoice.price">
and here's the directive:
directive("limitToNumber", [function() {
return {
restrict: "A",
link: function(scope, elem, attrs) {
var limit = parseInt(attrs.limitToNumber);
var number_of_decimals = parseInt(attrs.numberOfDecimals);
var digit_array = [];
angular.element(elem).on("keydown", function(e) {
console.log(this);
});
}
};
}]).
I tried different approaches, the main problem is that this.value does not contain ".".
For example if the input in the form is "12":
console.log(this.value) // -> 12
But if the input in the form is "......12.....":
console.log(this.value) // -> "" empty string
But I noticed that printing just "this" return the whole html of the input:
<input required type='number' limit-to-number="3" number-of-decimals="2" ng-required="true" ng-model="invoice.price" name="price" aria-invalid="false">
#shadow-root (user-agent)
<div id="text-field-container" pseudo="-webkit-textfield-decoration-container">
<div id="editing-view-port">
<div id="inner-editor">12.</div>
...
In the div with id="inner-editor" I can see the exact value of the input field. The problem now is that this is not working:
console.log(this.findElementById("inner-editor")); // -> Uncaught TypeError: this.getElementById is not a function
How can I extract that div value from the object "this" ?

You can use
<input type="number" step="0.01" max="999.99" min="0" required />
Of course you must validate input of user after submit (angular form validation foe example).
Try this:
.directive('limitToNumber', function () {
return {
restrict: 'A',
require: '?ngModel',
link: function (scope, element, attrs, modelCtrl) {
modelCtrl.$parsers.push(function (inputValue) {
// inputValue variable will contain the input box value
var limit = parseInt(attrs.limitToNumber);
var number_of_decimals = parseInt(attrs.numberOfDecimals);
var digit_array = [];
if (inputValue == undefined) return '';
// Your transformation code will be written here
// Assign the transformed value to transformedInput variable
var transformedInput = '';
if (transformedInput !== inputValue) {
// This will update the input box
modelCtrl.$setViewValue(transformedInput);
modelCtrl.$render();
}
return transformedInput;
});
}
};
});
Please let me know if it helps!

Directive not called on input change

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

AngularJs user validation making request for every characters

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

Firing ng-change only once

I need to call a function from ng-change on an input of type text only once, and on the first call it sets a boolean value to true, after that i want to disable the ng-change from firing whenever the input changes because all i need to do is to change a boolean to true
here is the controller
angular.module("app",[]).controller('FieldCtrl',['$scope',function($scope){
$scope.Value = '';
$scope.IsRequired = true;
$scope.HasBeenForTheFirstTime = false;
$scope.ValueChanged = function() {
$scope.HasBeenForTheFirstTime = true;
console.log("isFired");
};
}]);
and the html simply
<input type="text"
ng-model="Value"
value="{{Value}}"
ng-change="ValueChanged()">
one more thing is, is using ng-change the right thing in this case?
Using $watch...
angular.module("app",[]).controller('FieldCtrl',['$scope',function($scope){
$scope.Value = '';
$scope.IsRequired = true;
$scope.HasBeenEditedBefore = false;
$scope.UnWatch = $scope.$watch("Value",function(){
if($scope.Value.length > 0)
{
$scope.HasBeenEditedBefore = true;
$scope.UnWatch();
}
});
}]);
you can remove $scope.ValueChanged function and use the following code is enough.
<input type="text"
ng-model="Value"
value="{{Value}}"
ng-change="HasBeenForTheFirstTime=true" />

Categories