jQuery validation - Date not validation in Safari but in Chrome it does - javascript

Issue: jQuery validation is not working on Safari but it does on Google chrome, firefox.
The CMS that handles the form to sign up need the date in the following format: YYYY-MM-DD. How people are used to fill in the form is like: DD-MM-YYYY. So i order to manage that i used jQuery (https://jqueryui.com/datepicker/). I set the correct date using dateFormat and used the altFormat to change the appearance of the date. When submitting the form, the validator method: minAge16 should check if the user is 16 years or older. When i test it on Google Chrome or Firefix, it works fine and return the error message; you are not 16 years or older. But when i test it on Safari browser or iPhone, it keeps saying you are not 16 years or older. My guess it that it doesn't work since safari makes use of a different time format. Has anyone else faced the validation problem in Safari or Chrome and how did you manage to find a work around?
jQuery Datepicker:
$(document).ready(function() {
$( ".js-date-picker" ).datepicker({
dateFormat: "yy-mm-dd",
altFormat: "dd-mm-yy"
});
});
The form:
<form action="" method="post" class="text-center py-4 js-validate" id="signup">
<div class="row">
<div class="col-12 mb-2">
<label class="input">
<input type="text"
name="data[invoice][birthdate]"
placeholder="Date of birth*"
class="input__field js-date-picker mt-2" required value="">
</label>
</div>
</div>
<button type="submit" name="button" class="d-block mx-auto button mt-4 mt-lg-5">Submit</button>
Javascript:
$(document).ready(function() {
// Check if browser supports date input
var datePickerFormatMessage = '';
var inputField = document.createElement('input');
inputField.setAttribute('type', 'date');
if(inputField.type != 'date') {
datePickerFormatMessage = ' (JJJJ-MM-DD)';
}
// Check if the user entered a valid date
$.validator.addMethod('validDate', function(value, element) {
var regEx = /^\d{4}-\d{2}-\d{2}$/;
if(!value.match(regEx)) {
return false; // Invalid format
}
var today = new Date();
var date = new Date(value);
if(Number.isNaN(date.getTime())) {
return false; // Invalid date
} else if ((today.getFullYear() - date.getFullYear()) > 110) {
return false; // Invalid age
}
return date.toISOString().slice(0, 10) === value;
}, ('Please enter a valid date' + datePickerFormatMessage));
$.validator.addMethod('minAge16', function(value, element) {
var birthDate = new Date(value);
var eighteenYearsAgo = new Date();
eighteenYearsAgo.setFullYear(eighteenYearsAgo.getFullYear() - 16);
return (birthDate < eighteenYearsAgo);
}, 'You must be atleast 16 years or older.');
$('.js-validate').each(function() {
$(this).validate({
rules: {
'data[invoice][birthdate]': {
validDate: true,
minAge16: true
}
},
messages: {
'data[buyer][birthdate]': {
date: 'Fill in a valid date' + datePickerFormatMessage
}
},
});
});
});
Here it goes wrong:
$.validator.addMethod('minAge16', function(value, element) {
// here it goes wrong when i debug in safari, i am not getting a correct date back to check the difference
var birthDate = new Date(value);
var eighteenYearsAgo = new Date();
eighteenYearsAgo.setFullYear(eighteenYearsAgo.getFullYear() - 16);
return (birthDate < eighteenYearsAgo);
}, 'You must be atleast 16 years or older.');

Found the solution:
Safari does not accept:
new Date('01-10-2000');
So what i did is:
var birthDate = new Date('01-10-2000'.replace(/-/g, "/"));
Afterwards i made sure that all dates have the correct format with UTCString();
birthDate.toUTCString();
This post helped me found the solution:
Invalid date in safari

Related

Age validation using dd/mm/yyyy

I am trying to validate a form I have for age validating using javascript but it doesn't seem to be working.. not sure why.
Basically the date of birth is entered : dd/mm/yyyy and I need to make sure that in order to submit the form the age of the person is between 15 - 80.. I have tried validating this way but doesn't seem to work.
Html
<label>
Date of birth:
<input type="text" name="birth date" id="DOB"
placeholder="dd/mm/yyyy" maxlength="10" pattern="\d{1,2}\/\d{1,2}\/\d{4}"
required="required"/>
</label>
Javascript
var birthDate = document.getElementById("DOB").value;
if (2019 - birthDate < 15 || 2019 - birthDate > 80) {
errMsg =errMsg + "your age must be between 15 and 80\n";
result = false;
}
if (errMsg !== "") {
alert(errMsg);
}
return result;
So, based on your comment, you have a text box as such:
<form>
<input type="text" name="birth date" id="DOB" placeholder="dd/mm/yyyy" maxlength="10" pattern="\d{1,2}\/\d{1,2}\/\d{4}" required="required"/></label>
</form>
Therefore, document.getElementById("DOB").value; will be of the format dd/mm/yyyy.
So, if you are just checking the year, this should do the trick:
onload = function() {
var form = document.getElementById("form"); //assuming this is your form's ID
form.onsubmit = validate;
}
function checkAge() {
var currentYear = new Date().getFullYear();
var birthDate = document.getElementById("DOB").value;
var errMsg = ""; //this line was missing from my code, and preventing it from working.
//turning "dd/mm/yyyy" into an array of the form { "dd", "mm", "yyyy" }, and taking the "yyyy" part
var birthYear = birthDate.split("/")[2];
var age = currentYear - birthYear;
if (age < 15 || age > 80) {
errMsg =errMsg + "your age must be between 15 and 80\n";
result = false;
}
if (errMsg !== "") {
alert(errMsg);
return false; //form won't submit
}
return true; //form will submit
}
As you can see, I also used getFullYear() so that we don't hard code a fixed current year.
But it would probably be cleaner if you use an <input type="date"> element rather than a text box.
document.getElementById("DOB").value is a string, not a date, so you need to convert it. For that there are different methods; one is to convert the string to YYYY-MM-DD format and pass that to the Date constructor.
Moreover, someone's age changes on their birthday, not at the change of a calendar year, so you need a different logic to get their age. One way is to precalculate the date of 15 years ago and of 81 years ago, and test that the entered birthdate lies between these two extremes.
var DOB = document.getElementById("DOB");
var output = document.getElementById("output");
var go = document.getElementById("go");
var fifteenYearsAgo = new Date();
fifteenYearsAgo.setFullYear(fifteenYearsAgo.getFullYear() - 15);
var eightyOneYearsAgo = new Date();
eightyOneYearsAgo.setFullYear(eightyOneYearsAgo.getFullYear() - 81);
// Function returns true when age is OK, false otherwise
function check() {
var birthDate = new Date(DOB.value.replace(/(..)\/(..)\/(....)/, "$3-$2-$1"));
return birthDate <= fifteenYearsAgo && birthDate > eightyOneYearsAgo;
}
go.addEventListener("click", function() {
if (check()) {
output.textContent = "Your age is OK";
} else {
output.textContent = "Your age must be between 15 and 80";
}
});
Birthdate: <input id="DOB"><button id="go">Go</button>
<div id="output"></div>
HTML5
If you are certain about your clients having HTML5 support, then use type="date" for your input element, and dynamically set the min and max attributes of a date typed input element and rely on form validation. If the form gets into the submit handler, you can be sure the validations passed:
var DOB = document.getElementById("DOB");
var form = document.querySelector("form");
var fifteenYearsAgo = new Date();
fifteenYearsAgo.setHours(0, 0, 0, 0);
fifteenYearsAgo.setFullYear(fifteenYearsAgo.getFullYear() - 15);
var eightyOneYearsAgo = new Date();
eightyOneYearsAgo.setHours(0, 0, 0, 0);
eightyOneYearsAgo.setFullYear(eightyOneYearsAgo.getFullYear() - 81);
// Border case: in leap years next condition could be false
if ((new Date()).getDate() === eightyOneYearsAgo.getDate()) {
eightyOneYearsAgo.setDate(eightyOneYearsAgo.getDate()+1);
}
DOB.setAttribute("min", eightyOneYearsAgo.toLocaleString("se").slice(0,10));
DOB.setAttribute("max", fifteenYearsAgo.toLocaleString("se").slice(0,10));
form.addEventListener("submit", function(e) {
alert("Your age is OK");
e.preventDefault();
return false;
});
function validationMessage() {
DOB.setCustomValidity("");
const msg = DOB.checkValidity() ? ""
: DOB.validity.valueMissing ? "This field is required"
: DOB.validity.rangeOverflow ? "You must be at least 15"
: DOB.validity.rangeUnderflow ? "You must be at most 80"
: "Enter a valid date"
DOB.setCustomValidity(msg);
}
DOB.addEventListener("input", validationMessage);
validationMessage();
<form>
<label>
Date of birth:
<input type="date" name="birth date" id="DOB" required="required"/>
</label>
<button id="go">Go</button>
</form>
document.getElementById("DOB").value; will give you something like 10/10/2000 and performing arithmetic operations on this string will result in NaN. That must be causing an issue.
Validating date is a more complex than you imagine. There are a lot of things that you need to consider. Use libraries like moment to help you in validating dates.
Edit: Use moment's Difference method to calculate the age.
You can use built in min and max props for input. Try something like this.
<p>Enter a number and click OK:</p>
<input id="id1" type="number" min="15" max="80" required>
<button onclick="myFunction()">OK</button>
<p>If the age is less than 15 or greater than 80, an error message will be
displayed.</p>
<p id="demo"></p>
<script>
function myFunction() {
var inpObj = document.getElementById("id1");
if (!inpObj.checkValidity()) {
document.getElementById("demo").innerHTML = inpObj.validationMessage;
} else {
document.getElementById("demo").innerHTML = "Input OK";
}
}
</script>
Theoretically this should work.
Since you are using pattern and required I assume that you want the error message (if the age is out of range) to be shown to the user in the same way as if the entered date is in the wrong format or is missing. That can be achieved with setCustomValidity.
If you add an event listener of the input event on the DOB-element, you can run a function that checks if the entered age is in rage. It will set the custom error message if the age is out of range, or if the entered date is invalid. Otherwise it let the browser handle the error (if it is missing or of wrong pattern).
function validateDOB(event) {
const minAge = 15, maxAge = 80;
// No custom error message. The broswer will complain if the input isn't in the
// correct form, or if the value is missing since the element has "pattern" and
// and "required".
this.setCustomValidity('');
// Check if there are any other errors
if ( !this.validity.valid ) return;
// Check format of input, and split it into parts
const dobArrayText = this.value.trim().match(/^(\d{1,2})\/(\d{1,2})\/(\d{4})$/);
// dobArrayText is null if not in correct format. Let the broswer handle the error.
if (!dobArrayText) return;
// Decode dobArrayText to numeric values that can be used by the Date constructor.
const dob = {
year : +dobArrayText[3],
month : (+dobArrayText[2]) - 1, // month is zero based in date object.
day : +dobArrayText[1]
}
const dobDate = new Date( dob.year, dob.month, dob.day );
// Check validity of date. The date object will accept 2000-99-99 as input and
// adjust the date to 2008-07-08. To prevent that, and make sure the entered
// dobDate is a valid date, I check if the entered date is the same as the parsed date.
if (
!dobDate
|| dob.year !== dobDate.getFullYear()
|| dob.month !== dobDate.getMonth()
|| dob.day != dobDate.getDate()
) {
this.setCustomValidity('Invalid date');
return;
}
// Calc minAgeDate and maxAgeDate
const minAgeDate = new Date(dob.year + minAge, dob.month, dob.day);
const maxAgeDate = new Date(dob.year + maxAge, dob.month, dob.day);
// Get todays date and set Hours, Minutes, Seconds and Milliseconds to 0.
const todayTimestamp = new Date().setHours(0,0,0,0);
// Check validity and set a custom error message if needed.
if ( todayTimestamp < minAgeDate ) {
this.setCustomValidity(`Sorry, you must be older than ${minAge} years old`);
}
else if ( todayTimestamp >= maxAgeDate ) {
this.setCustomValidity(`Sorry, you must be younger than ${maxAge} years old`);
}
}
function formInit() {
document.getElementById('DOB').addEventListener("input", validateDOB);
}
window.addEventListener('DOMContentLoaded', formInit);
<form id="myForm">
<label>
Date of birth:
<input type="text" name="birth_date" id="DOB"
placeholder="dd/mm/yyyy" maxlength="10" pattern="\d{1,2}\/\d{1,2}\/\d{4}"
required="required"/>
</label>
<button type="submit">Submit</button>
</form>

Datepicker validation not functioning on first try

I am currently working on a site using MEAN. In this site, I am using html5 datepicker but since it is not supported on some browsers, I used jquery datepicker as fallback and successfully managed to make it work.
Another thing I want is to display an error message if the user's selected date is valid. A date is valid if it is between 1900-01-01 and the current date.
Now, the problem is whenever I select a date for the first time, I am getting the error message even though I selected a valid date. And upon selecting a valid date for the second time, the error message disappears. On the third try, I selected an invalid date but the error doesn't show. On the fourth try, I selected a valid date but the error displays. To make it short, the validation applies to the previous input and not on the current input.
Below is the code on my controller:
var elem = document.createElement('input');
elem.setAttribute('type', 'date');
if ( elem.type === 'text' ) {
$('#contactBirthdate').datepicker({
dateFormat: "yy-mm-dd"
});
}
$scope.checkDate = function() {
console.log('Entered check date funtion');
var now = new Date();
var minDate = new Date('1900-01-01');
var inputDate;
if ( elem.type === 'text' ) {
$scope.appointment.birthday = new Date($( "#contactBirthdate" ).val());
console.log('input date not supported');
inputDate = new Date($scope.appointment.birthday);
} else {
inputDate = new Date($scope.appointment.birthday);
}
console.log('inputDate ' + inputDate);
if (inputDate < now && inputDate > minDate) {
$scope.isValidDate = true;
} else {
$scope.isValidDate = false;
}
console.log($scope.isValidDate);
};
And in my HTML
<div class="form-field">
<input name="contactBirthdate" type="date" min="1900-01-01" max="{{minAge | date: 'yyyy-MM-dd'}}" id="contactBirthdate" placeholder="Your Birthdate"
value="" class="full-width" ng-model="appointment.birthday" required="" step="1" ng-blur="checkDate()" onkeydown="return false">
<label ng-show="contactForm.contactBirthdate.$touched && !isValidDate" id="contactName-error" class="error" for="contactBirthdate">
Invalid Birthdate</label>
</div>
I really hope someone can help me with this one.

JS: How to use convert string to date and then use every method to check false input?

Picture input form where user submits from 1 up to 4 dates within same month. I have set like this:
//hardcoeding rage dates from March 6 to March 9.
app.controller...
$scope.rangeValidator = {
startDate: '06/03/2017',
endDate: '09/03/2017'
}
//Setting calendar available start and end date.
$scope.initCalendar = function() {
$('#reclamoFecha .input-group.date').datepicker({
multidate: true,
multidateSeparator: ",",
format: "dd/mm/yyyy",
startDate: $scope.rangeValidator.startDate,
endDate: $scope.rangeValidator.endDate,
language: "es"
});
};
I want to check if ONLY inputs of dates in this range are submitted, and if false, an alert is executed. When user datepicker input it is logged as a String, also when many dates are submitted each date becomes part of the logged string, so I had to split into an array.
// returns: "06/03/2017,07/03/2017,08/03/2017,09/03/2017"
$scope.validRangeDate = $rootScope.reclamo.fechas.split(',');
$scope.validateForm(function() {
$scope.validRangeDate = $rootScope.reclamo.fechas.split(',');
console.log($scope.validRangeDate);
//returns: ['06/03/2017','07/03/2017','08/03/2017','09/03/2017',]
so what I need to do is a conditional where I can check the if eg: 20/03/2017 is submited it triggers an alert.
I was thinking about setting a range between startdate and enddate with "every" method for the array.
I´m not quite sure if I should convert the string to Date before. Also not quite sure how to use that method on a function.
To check a date in a range you could create a custom validation method like:
$.validator.addMethod("dateRange", function(value, element, params) {
try {
var date = new Date(value);
if (date >= params.from && date <= params.to) {
return true;
}
} catch (e) {}
return false;
}, 'Date out of range');
Then add the relative class rules in order to pass the two parameters for the valid range:
$.validator.addClassRules({
myDateFieldRangeValidate: {
dateRange: {
from: fromDate,
to: toDate
}
}
});
Finally add the validator to your field / fields:
$("#myField").addClass("myDateFieldRangeValidate");
See following complete example:
var fromDate = new Date("2017-03-01");
var toDate = new Date("2017-03-31");
$.validator.addMethod("dateRange", function(value, element, params) {
try {
var date = new Date(value);
if (date >= params.from && date <= params.to) {
return true;
}
} catch (e) {}
return false;
}, 'Date out of range');
$.validator.addClassRules({
myDateFieldRangeValidate: {
dateRange: {
from: fromDate,
to: toDate
}
}
});
$("#myField").addClass("myDateFieldRangeValidate");
$("#frm1").validate();
$("#btnValidate").click(function() {
console.log($("#frm1").valid())
});
jQuery(function($) {
var validator = $('#frm1').validate({
rules: {},
messages: {}
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.16.0/jquery.validate.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.16.0/additional-methods.min.js"></script>
<form id="frm1">
Date
<input type="text" id="myField" value="16 Feb 2017">
<input type="button" id="btnValidate" value="Validate">
</form>
I hope it helps you, bye.

ng-disabled in Angular not working

In My Angular UI I want to disable a submit button if
1) All the inputs are null or empty
2) If the endDate field is less than the startDate itself
What I did is ...
<input type="submit" class="btn btn-default pull-right" style="width:100px;" value="Submit"
ng-disabled="groupMembershipUserInputForm.$invalid || !(!!groupmembership.chapterCode || !!groupmembership.groupCode ||
!!groupmembership.groupName || !!groupmembership.createdBy ||
!!groupmembership.createdDate || !!groupmembership.startDate ||
!!groupmembership.endDate || !!groupmembership.losCode
|| groupmembership.compareAgainstStartDate(groupmembership.endDate) )" />
All the strings empty/null checks are working fine except the date compare check .
In my controller the method looks like
$scope.groupmembership.compareAgainstStartDate = function (item) {
var startDate = $filter('date')(new Date($scope.groupmembership.startDate), 'MM/dd/yyyy');
var endDate = $filter('date')(new Date($scope.groupmembership.endDate), 'MM/dd/yyyy');
if (endDate < startDate) {
$scope.groupmembership.toggleInvalidInput = true;
}
else
$scope.groupmembership.toggleInvalidInput = false;
return $scope.groupmembership.toggleInvalidInput;
};
It is being hit , but I don't know why the disabling not happening if the date compare fails .
Please help me .
So first :
All the inputs are null or empty
For this just add a required to all your input/select/...
If you do so groupMembershipUserInputForm.$invalid will be true if one of the required fields is not filled.
This will simplify greatly you ng-disabled to the following :
ng-disabled="groupMembershipUserInputForm.$invalid ||
groupmembership.compareAgainstStartDate(groupmembership.endDate)"
This is a first valid working step. Now if you want to go further you could create a directive and have something like :
<input ng-model="afterDate" date-greater-than="beforeDate"/>
This will be usefull if you have other forms than need this. If you're interested to do this i suggest you to google something like "angular js custom validation form directive" and if you have trouble with that directive, after trying on your own, come back to us into another question.
FInally if you master custom validation form you could use angular-message. it's a little addon specifically designed to display error from forms.
Here is a sample code from https://scotch.io/tutorials/angularjs-form-validation-with-ngmessages :
<form name="myForm">
<input
type="text"
name="username"
ng-model="user.username"
ng-minlength="3"
ng-maxlength="8"
required>
<div ng-messages="userForm.name.$error">
<p ng-message="minlength">Your name is too short.</p>
<p ng-message="maxlength">Your name is too long.</p>
<p ng-message="required">Your name is required.</p>
<p ng-message="myCustomErrorField">Your name is <your custom reason></p>
</div>
<input type="submit" ng-disabled="myForm.$invalid"/>
</form>
Your logic pretty much right, I have doubt on your $scope.groupmembership.startDate and $scope.groupmembership.endDate because if I provide correct dates, then it is working as expected. Can you please try by providing some constant date to verify whether your function is behaving properly or not. For me it is working fine with actual date values.
$scope.startDate = $filter('date')(new Date("07/02/2016"), 'MM/dd/yyyy');
$scope.endDate = $filter('date')(new Date("0710/2016"), 'MM/dd/yyyy');
In your example dates are string type so you may not get correct result. To compare date first convert it to time using getTime() that will give you exact result. No need to use filter for date check.
just use like:
$scope.groupmembership.compareAgainstStartDate = function () {
var startDate = new Date($scope.groupmembership.startDate);
var endDate = new Date($scope.groupmembership.endDate);
if (endDate.getTime() < startDate.getTime()) {
$scope.groupmembership.toggleInvalidInput = true;
}
else
$scope.groupmembership.toggleInvalidInput = false;
return $scope.groupmembership.toggleInvalidInput;
};
Just convert startdate and enddate to milliseconds, and compare them.
Try the below code once:
$scope.groupmembership.compareAgainstStartDate = function () {
var startDate = new Date($scope.groupmembership.startDate).getTime();
var endDate = new Date($scope.groupmembership.endDate).getTime();
if (endDate < startDate) {
$scope.groupmembership.toggleInvalidInput = true;
} else {
$scope.groupmembership.toggleInvalidInput = false;
}
return $scope.groupmembership.toggleInvalidInput;
};

Javascript to validate date entered

I am new to Javascript programming and I am trying to validate a date entered into an <input> from a calender snippet which is obtained from an external Javascript file. I am trying to validate the date to check if the user entered a past date. If the entered date is a past date, then I need to print a warning message to enter a valid date in future period.
I accept input date field in following HTML code:
<input size="12" id="inputField" name="inputField" autofocus="" type="date" oninput="return dateValidate(inputField)"/>
My Javascript function to validate input date is:
<script type="text/javascript">
function dateValidate(inputField)
{
var v2 = document.getElementById('inputField');
var pickeddate = new Date(v2.Value);
todayDate = new Date();
if(pickeddate > todayDate){
return true;
} else {
alert("Enter a valid Date");
}
}
But this code doesn't seem to be working. I want this Javascript function to be run when I enter a past date in the <input> field and tab out. I want to validate date when it is entered in the field, not when the form is submitted.
It is not working since there is a issue in your code, just replace this:
var pickeddate = new Date(v2.Value);
with this:
var pickeddate = new Date(v2.value); // 'value' should be in lower case
Since, it was not correct, the pickeddate was always undefined and code didn't worked.
You may try this
HTML
<input size="12" id="inputField" name="inputField" autofocus="" type="date" onblur="return dateValidate(this)"/>
JS
function dateValidate(inputField)
{
var pickeddate = new Date(inputField.value);
var todayDate = new Date();
if( pickeddate > todayDate )
{
return true;
}
else
{
alert("Enter a valid Date");
}
}
DEMO.

Categories

Resources