When capturing information for insertion into a database, or use in
other processing, it's important to control what the user can enter.
Otherwise you can end up with values in the database that have no
relation to reality.
Checking for valid format
In this example, the date fields will only accept input that matches
the pattern 'dd/mm/yyyy' (this could just as easily be changed to
'yyyy-mm-dd' or 'mm/dd/yyyy'). The time field will allow input starting
with 'hh:mm' following by an optional 'am' or 'pm'. The fields can also
be empty.
The code behind the form is as follows:
function checkForm(form)
{
// regular expression to match required date format
re = /^\d{1,2}\/\d{1,2}\/\d{4}$/;
if(form.startdate.value != '' && !form.startdate.value.match(re)) {
alert("Invalid date format: " + form.startdate.value);
form.startdate.focus();
return false;
}
if(form.enddate.value != '' && !form.enddate.value.match(re)) {
alert("Invalid date format: " + form.enddate.value);
form.enddate.focus();
return false;
}
// regular expression to match required time format
re = /^\d{1,2}:\d{2}([ap]m)?$/;
if(form.starttime.value != '' && !form.starttime.value.match(re)) {
alert("Invalid time format: " + form.starttime.value);
form.starttime.focus();
return false;
}
alert("All input fields have been validated!");
return true;
}
For each field in the form (first the dates, then the time field), a
check is made as to whether the input is blank. If not, the input is
compared to the regular expression. The expressions use a pre-defined
class \d which represents any numeric character (0-9).
If you wanted to be really finicky the regular expression to match a
date could also be written as:
re = /^[0-3]?[0-9]\/[01]?[0-9]\/[12][90][0-9][0-9]$/
If the input doesn't match the regular expression then an error
message is presented, the routine stops the form from submitting by
returning a false value and the focus is moved to the relevant
form field.
If all tests are passed, then a value of true is returned
which enables the form to be submitted.
Note: The routine does not check that the date or time
input is valid, just that it matches the required format.
Checking for valid input values
Once you're in control of the input format, it's a lot easier to
check that the values are actually valid. The function has been
improved now so that the day, month and year values are checked to
ensure that they're in the right ball-bark (ie. 1-31 for the day and
1-12 for the month). Also the year must be between 1902 and the current
year.
The year limitation would be used if you were asking for a date of
birth or date of some recent event. If you're setting up a calendar of
future events you would check that the year is the current year or
greater.
The code behind the form now is as follows:
function checkForm(form)
{
// regular expression to match required date format
re = /^(\d{1,2})\/(\d{1,2})\/(\d{4})$/;
if(form.startdate.value != '') {
if(regs = form.startdate.value.match(re)) {
if(regs[1] < 1 || regs[1] > 31) {
alert("Invalid value for day: " + regs[1]);
form.startdate.focus();
return false;
}
if(regs[2] < 1 || regs[2] > 12) {
alert("Invalid value for month: " + regs[2]);
form.startdate.focus();
return false;
}
if(regs[3] < 1902 || regs[3] > (new Date()).getFullYear()) {
alert("Invalid value for year: " + regs[3] + " - must be between 1902 and " + (new Date()).getFullYear());
form.startdate.focus();
return false;
}
} else {
alert("Invalid date format: " + form.startdate.value);
form.startdate.focus();
return false;
}
}
if(form.enddate.value != '') {
if(regs = form.enddate.value.match(re)) {
if(regs[1] < 1 || regs[1] > 31) {
alert("Invalid value for day: " + regs[1]);
form.enddate.focus();
return false;
}
if(regs[2] < 1 || regs[2] > 12) {
alert("Invalid value for month: " + regs[2]);
form.enddate.focus();
return false;
}
if(regs[3] < 1902 || regs[3] > (new Date()).getFullYear()) {
alert("Invalid value for year: " + regs[3] + " - must be between 1902 and " + (new Date()).getFullYear());
form.enddate.focus();
return false;
}
} else {
alert("Invalid date format: " + form.enddate.value);
form.enddate.focus();
return false;
}
}
// regular expression to match required time format
re = /^(\d{1,2}):(\d{2})([ap]m)?$/;
if(form.starttime.value != '') {
if(regs = form.starttime.value.match(re)) {
if(regs[3]) {
if(regs[1] < 1 || regs[1] > 12) {
alert("Invalid value for hours: " + regs[1]);
form.starttime.focus();
return false;
}
} else {
if(regs[1] > 23) {
alert("Invalid value for hours: " + regs[1]);
form.starttime.focus();
return false;
}
}
if(regs[2] > 59) {
alert("Invalid value for minutes: " + regs[2]);
form.starttime.focus();
return false;
}
} else {
alert("Invalid time format: " + form.starttime.value);
form.starttime.focus();
return false;
}
}
alert("All input fields have been validated!");
return true;
}
expand code box
If you're not already familiar with regular expressions, then this
might be getting a bit complicated. Basically, for each of the regular
expression tests, an array is returned holding each component of the
pattern that we've matched.
For example, when the date is checked, the return value,
regs, is an array with elements 1 through 3 containing the day,
month and year components of the input string. For the time check, the
array returned includes the hour (pos 1), minutes (pos 2) and,
optionally, the am/pm string (pos 3).
Each of these values is then tested against an allowed range (days: 1
- 31; months: 1 - 12; years: 1902 - present; ...).
Note: This still doesn't confirm that the date
is valid. To do that you need to take into account variation between
calendar months and leap-/non leap-years which is beyond the scope of
this example. The following article on Form Validation: Credit Cards and
Dates addresses this issue a bit better.
Modularising the code
As we've seen before, creating re-usable functions can significantly
reduce the size of your JavaScript code. These functions can even be
included from an external javascript file so that the browser can cache
them, and so the programmer isn't always copying and pasting.
In this case, we've created a stand-alone functions which will
validate a date field:
// Original JavaScript code by Chirp Internet: www.chirp.com.au
// Please acknowledge use of this code by including this header.
function checkDate(field)
{
var allowBlank = true;
var minYear = 1902;
var maxYear = (new Date()).getFullYear();
var errorMsg = "";
// regular expression to match required date format
re = /^(\d{1,2})\/(\d{1,2})\/(\d{4})$/;
if(field.value != '') {
if(regs = field.value.match(re)) {
if(regs[1] < 1 || regs[1] > 31) {
errorMsg = "Invalid value for day: " + regs[1];
} else if(regs[2] < 1 || regs[2] > 12) {
errorMsg = "Invalid value for month: " + regs[2];
} else if(regs[3] < minYear || regs[3] > maxYear) {
errorMsg = "Invalid value for year: " + regs[3] + " - must be between " + minYear + " and " + maxYear;
}
} else {
errorMsg = "Invalid date format: " + field.value;
}
} else if(!allowBlank) {
errorMsg = "Empty date not allowed!";
}
if(errorMsg != "") {
alert(errorMsg);
field.focus();
return false;
}
return true;
}
Note: To convert to mm/dd/yyyy (US format)
just swap regs[1] and regs[2] in the above
code.
We're STILL not checking that the date entered actually exists. For
an idea of how that might be done read the next article Form Validation: Credit Cards and
Dates.
And another function that will validate a time input:
// Original JavaScript code by Chirp Internet: www.chirp.com.au
// Please acknowledge use of this code by including this header.
function checkTime(field)
{
var errorMsg = "";
// regular expression to match required time format
re = /^(\d{1,2}):(\d{2})(:00)?([ap]m)?$/;
if(field.value != '') {
if(regs = field.value.match(re)) {
if(regs[4]) {
// 12-hour time format with am/pm
if(regs[1] < 1 || regs[1] > 12) {
errorMsg = "Invalid value for hours: " + regs[1];
}
} else {
// 24-hour time format
if(regs[1] > 23) {
errorMsg = "Invalid value for hours: " + regs[1];
}
}
if(!errorMsg && regs[2] > 59) {
errorMsg = "Invalid value for minutes: " + regs[2];
}
} else {
errorMsg = "Invalid time format: " + field.value;
}
}
if(errorMsg != "") {
alert(errorMsg);
field.focus();
return false;
}
return true;
}
and it's now clear to just about anyone what main validation function
is doing:
function checkForm(form)
{
if(!checkDate(form.startdate)) return false;
if(!checkTime(form.starttime)) return false;
if(!checkDate(form.enddate)) return false;
return true;
}
The output will be almost identical to the previous example.
We could even write the checkForm function now as:
function checkForm(form)
{
return checkDate(form.startdate) && checkTime(form.starttime) && checkDate(form.enddate);
}
Adjusting the code for different date formats
Visitors from some countries may find it confusing that we're using
the dd/mm/yyyy date format instead of the American or other
standards. Modifying the code to account for these differences is quite
simple and involves only minor changes.
US Date Format MM/DD/YYYY
In the checkDate function above you only need to replace
references to regs[1] with regs[2] and vice-versa to
reflect the change in order of the day and month values.
European Format YYYY-MM-DD
In the checkDate function above you only need to change the
regular expression (re) to /^(\d{4})-(\d{1,2})-(\d{1,2})/ and
then replace references to regs[1] with regs[3] and
vice-versa as the year and day values have now changed position.
Related Articles
|