...

View Full Version : Validating Date with JS using Reg Expression



javanewbie7
12-08-2012, 03:19 AM
Hey all,

I've been practicing JS and today I decided to create a "To Do" List.

So far, I've gotten everything working properly except the validDate function which makes sure the date entered is in a valid format (12.12.2012 or 12/12/2012, etc.) However, it's not working in any browsers. I used Chrome Dev tools and I keep getting an error "addDueDate" is not defined. Any idea but I'm doing wrong. I'm very new to Reg Expressions so i very well could have messes something up.



<html>

<head>
<title>Untitled</title>
</head>
<body>
<form name="list">
<input type="text" name="datedue" value="Date Due" /> <br />
<input type="text" name="todo" value="Task" /> <br />
<input type="button" name="button1" value="Submit" onclick="addList(); validDate()"/> <br />
</form>
<div id="todolist">
<table>
<tr>
<td>Due Date </td>
<td>Task</td>
</tr>
</table>
</div>

<script type="text/javascript">
function addList () {
var addDueDate=document.list.datedue.value;
var addToList=document.list.todo.value;
document.getElementById("todolist").innerHTML= "<table><tr><td> Due Date </td><td>Task</td></tr><tr><td>" + addDueDate + "</td><td> " + addToList +"</td></tr></table>";
}


var checkDateDue=document.list.datedue;
var checkToDo= document.list.todo;

checkDateDue.onfocus= function() {
if(checkDateDue.value=="Date Due") {
checkDateDue.value="";
}
}
checkToDo.onfocus= function() {
if(checkToDo.value=="Task") {
checkToDo.value="";
}
}

checkDateDue.onblur= function() {
if (checkDateDue.value =="") {
alert("please enter the due date");
checkDateDue.value="Date Due";
}
}

checkToDo.onblur=function() {
if (checkToDo.value=="") {
alert("Please enter your task");
checkToDo.value="Task";
}
}

function validDate() {
var re= /^\d{2}[.\/-]\d{2[.\/-]\d{4}$/;
if (re.test(addDueDate)== false) {
alert("please enter a valid date");
}
}
</script>

</html>

Old Pedant
12-08-2012, 03:40 AM
The only place you have defined addDueDate is in this code:


function addList () {
var addDueDate=document.list.datedue.value;
var addToList=document.list.todo.value;
document.getElementById("todolist").innerHTML= "<table><tr><td> Due Date </td><td>Task</td></tr><tr><td>" + addDueDate + "</td><td> " + addToList +"</td></tr></table>";
}

But that variable is FUNCTION SCOPE, meaning that as soon as the addList() function is finished running, that variable is gone into the ether. Zap. Non-existent.

You could move the variable to global scope, but I think that's a bad idea.

A little extra code isn't going to hurt, especially if it keeps intent clear:


function validDate() {
var re= /^\d{2}[.\/-]\d{2[.\/-]\d{4}$/;
if (re.test(document.list.datedue.value)== false) {
alert("please enter a valid date");
}
}

NOW...there's another problem: You don't DO this validation until *AFTER* the item has ALREADY been "published" in the <table>. (And, by the by, it's bad practice to use innerHTML to generate an entier <table>, most experts would say.)

So wouldn't it make more sense to simply incorporate the test into the the addList( ) function and then *NOT* publish to the <table> if the date is invalid?

*NOW* you could simply do:


function addList () {
var addDueDate=document.list.datedue.value;
var re= /^\d{2}[.\/-]\d{2[.\/-]\d{4}$/;
if ( ! re.test(addDueDate) ) {
alert("please enter a valid date");
return;
}
var addToList=document.list.todo.value;
document.getElementById("todolist").innerHTML= "<table><tr><td> Due Date </td><td>Task</td></tr><tr><td>" + addDueDate + "</td><td> " + addToList +"</td></tr></table>";
}

And get rid of your validDate() function and the call to it.

Old Pedant
12-08-2012, 03:42 AM
Oh...and as another minor comment: Named <form>s are considered obsolete. You should give the <form> an id instead and use document.getElementById() to "find" the form. Of document.forms[0] and forget the id if you know you will only have one <form> on the page.

javanewbie7
12-08-2012, 04:29 AM
Oh...and as another minor comment: Named <form>s are considered obsolete. You should give the <form> an id instead and use document.getElementById() to "find" the form. Of document.forms[0] and forget the id if you know you will only have one <form> on the page.

Thanks so much. All of this was very useful information. I will make the changes.

felgall
12-08-2012, 05:01 AM
alert is for debugging only - you should display the error message in the web page itself.

Philip M
12-08-2012, 08:53 AM
function validDate() {
var re= /^\d{2}[.\/-]\d{2[.\/-]\d{4}$/;
if (re.test(addDueDate)== false) {
alert("please enter a valid date");
}
}


That checks if the format of the date is correct, (but note that USA and UK formats differ), but does not at all check whether the date is valid - not 56th February, or 26th of month 34, or year 9235. So not very useful.


<script type = "text/javascript">

function checkValidDate(yr,mmx,dd) {

if (yr <1910 || yr >2012) { // you may want to change 2012 to some other year!
alert ("Year is out of range")
return false;
}

mm = mmx-1; // remember that in Javascript date objects the months are 0-11
var nd = new Date(yr,mm,dd);

var ndmm = nd.getMonth();
if (ndmm != mm) {
alert (dd + "/" + mmx + "/" + yr + " is an Invalid Date!");
return false;
}
else {
alert (dd + "/" + mmx + "/" + yr + " is a Valid Date");
}
}

// USAGE:
checkValidDate(2012,2,20) // 20th February 2012 yyyy/mm/dd
checkValidDate(2012,2,31) // 31st February 2012 yyyy/mm/dd

</script>

As felgall says, alerts are used only for debugging/demonstration.

rnd me
12-08-2012, 09:09 AM
its a LOT less code, and a much better ux using HTML5:



<input
type="text"
name="datedue"
placeholder="Date Due"
pattern="^[012]*\d{1}[.\/][0123]*\d{1}[.\/]\d{1,2}$"
required
/>

you can do the other js too, but this should be your html starting point.
it works even with js disbled, and is more accessible than wresting with a script if you can't see everything at once, or at all for that matter...

Philip M
12-08-2012, 09:34 AM
I have to say - while some 80% of browsers still in use do not support HTML5, stick with Javascript. I do accept that the new input types included in HTML5 will degrade properly in older browsers. But they do not actually work. And different browser vendors have implemented support in different ways. IE support seems to be minimal.

And that pattern still does not check that the date is a valid one.

But I have found a useful script to emulate HTML5 functionality:-
https://github.com/ryanseddon/H5F

rnd me
12-08-2012, 10:11 AM
I have to say - while some 80% of browsers still in use do not support HTML5, stick with Javascript.

according to http://caniuse.com/#feat=form-validation, most users last month could expect the full validation set, and pattern is one of the most supported specific features of that.
considering tablets are the #1 wish-list item this year, expect IE to take a big hit by the 31st. i expect the numbers for jan, when they come out in feb, will show at least 2/3 if not 3/4. let's hope!

js should be used to provide graceful degradation.

but the html5 costs almost nothing, and even right now runs works often than not, and works for those poor folks with javascript disabled we hear soo much about.

i guess why code 5 lines when 20 will do right?


i didn't go all out say simply use <input type=date>, that's crazy talk!

AndrewGSW
12-08-2012, 10:34 AM
FWIW I find the HTML5 form attributes look (and perhaps behave) differently in different browsers; I know this is to be expected but sometimes the difference is quite discernible. This is tempting me to ignore (most of) them, use JS, but (of course) rely on server-side validation.

Philip M
12-08-2012, 10:44 AM
FWIW I find the HTML5 form attributes look (and perhaps behave) differently in different browsers; I know this is to be expected but sometimes the difference is quite discernible. This is tempting me to ignore (most of) them, use JS, but (of course) rely on server-side validation.

Once more, I agree totally with your comments.

007julien
12-08-2012, 05:31 PM
Regardless of the use of HTML5, I think it is unpleasant to impose a separator rather an other one, the choice should be left to the user. In addition, the user may prefer to use leading zeros...

Then I propose this regular expression (without ^ at the beginning nor $ at the end, to authorize spaces or other words) :

var rgx=/(\d(?=\D)|\d\d)[\D]*(\d(?=\D)|\d\d)[\D]*([1-9][0-9]{3})/;

It allows in particular :

One digit following by a separator or two digits,
Possibly one or some separator,
One digit following by a separator or two digits,
Possibly one or some separator,
Exactly 4 digits.

To validate a date, it is still advisable to verify that this one exists (See the source of this test page (http://mamisab.chez-alice.fr/validDate.html#)).

AndrewGSW
12-08-2012, 06:34 PM
Can't I just type two digits for the year :o

rnd me
12-08-2012, 09:09 PM
FWIW I find the HTML5 form attributes look (and perhaps behave) differently in different browsers; I know this is to be expected but sometimes the difference is quite discernible. This is tempting me to ignore (most of) them, use JS, but (of course) rely on server-side validation.



Once more, I agree totally with your comments.

i think it's time you guys had a second look.

try it live at http://danml.com/formtest.html


the following behaves exactly the same in ie, ff, ch, and op, i didn't test safari.

furthermore, it's a much nicer ui, provides color-based real-time feedback, hooks directly into the accessible API used by A.T. to communicate requirements to the visually and physically disabled, won't let wrong info be submitted (even w/o js), doesn't use alert(), doesn't use hand-coded validation-error messages (less work each field), errors message appear in the local language, bad entries text can survive a page refresh for a 2nd chance to correct errors without retyping, and allows custom css to style the various validity states.


Can your javascript do all that ?


<!DOCTYPE html><html>
<head>
<title>html5 form test</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style>
[id]:valid{ background:#cfc; }
[id]:invalid{ background:#fcc; outline: 0; box-shadow: none; }
</style>
</head>
<body>

<h1>htm5 form validation test </h1>
<form onsubmit="return false;">
<label for="datedue">
<b>Date Due</b>
<input type="text" name="datedue" id="datedue" placeholder="mm/dd/yy" title="mm/dd/yy"
pattern="^[01]*\d{1}[.\/][0123]*\d{1}[.\/]\d{2,4}$" required autofocus
/>
</label>
<input type=submit />
</form>

</body>
</html>


again, i test in the top 4 browsers, and the behavior is nearly identical, and very nice UX i must say, in all of them.

the only differences i noticed was the wording on the message, but it was all saying the same thing, and all of them correctly showed the title attrib as the suggestion:


FF/CH:

Please match the requested format:
mm/dd/yy

OP:

Please use the required format:
mm/dd/yy

IE:

You must use this format: mm/dd/yy



step back from past experiences for a moment, try the code in your favorite browsers, and ask yourself "is all that really worth typing 3 attribs?"

if you think not, and you would rather give your users a pop-up box that can leave them with no further communication if the check it's little checkbox, or you can have something that works almost everywhere, can easily be poly-filled for IE7/8, feels nice, behaves well, looks better, is highly accessible, and much less code to write for each app/field, then i suggest you take up photography or knitting or something besides web dev.


if nothing else, rip your config from the html and feed that to javascript instead of hand-coding strings and one-language error message; i can't see the harm at all.

AndrewGSW
12-08-2012, 09:24 PM
Just my opinion.. but a single input on a page doesn't convince. It's when trying to create an entire form on a page that the differences are more obvious.

Even so, it looks noticeably different in IE and, in fact, the submit button (which displays "Submit Query" and is therefore much wider) did nothing for me at all in IE9; the input-background is not pink. FF17 says "Please fill out this field" - it doesn't include the "dd/mm/yy". Added I am aware that not all of these points are directly relevant to HTML5.

Personally, I am not interested in debating the point - I'm just recounting my experience and thoughts. Besides, I am not rejecting HTML5 - I'm happy to use it where it is useful (autofocus, required..), but one cannot ignore the differences.

Philip M
12-08-2012, 09:27 PM
Terrific, but as I have often said, my customers insist on older browsers being supported. They are not interested in web sites that only work in IE9 or better.

I entered the date 47/89/3012 and it accepted it. :eek:

Shome mishtake, shurely.

I'll stick with my Javaascript.

rnd me
12-08-2012, 10:56 PM
Just my opinion.. but a single input on a page doesn't convince. It's when trying to create an entire form on a page that the differences are more obvious.

Even so, it looks noticeably different in IE and, in fact, the submit button (which displays "Submit Query" and is therefore much wider) did nothing for me at all in IE9; the input-background is not pink. FF17 says "Please fill out this field" - it doesn't include the "dd/mm/yy". Added I am aware that not all of these points are directly relevant to HTML5.

Personally, I am not interested in debating the point - I'm just recounting my experience and thoughts. Besides, I am not rejecting HTML5 - I'm happy to use it where it is useful (autofocus, required..), but one cannot ignore the differences.

a single input is what we're discussing here. Yes, different browsers render some form controls slightly differently, but that's got nothing to do with js/html5 validation. a submit label diff? really? you're just being mean.


the form has no reset css at all, this is a barebones example. at any rate, it's not as if using or not using javascript fixes browser rendering diffs you use against my solution.

for raw html, IE10,FF,Ch,and Op all look pretty close in my book. certainly a designer would want to skin the raw form, which is why my example uses <label> and <b> tags.

i'me not interested in debating either, but don't toss out arguments against something and run out the door, especially if most of them aren't germane.

Javascript is for behavior, CSS is for presentation, and HTML is for document/data definition.


I never ever said "don't use js", i think js can enhance HTML forms a lot.
The whole point is that you should be doing an "all of the above" approach.

Code to web standards, use JS to enhance the UI, gracefully degrade where standards or JS is absent, make sure it's accessible, D.R.Y., K.I.S.S., stand on the shoulders of giants, and don't re-invent the wheel, are all ambitions i try to follow. Humans are hypocritical by nature, folly is fun, but broadly speaking, I tend to lean towards those ideals, and i think HTML5 validation is a great starting point for any web app.

Considering the cost, i really just cannot see any reason not to add those few extra attribs. i just don't understand why you would advice readers not to use them. i really can't.

i would be fine with you saying "don't count on them", but to imply they should be used at all is plain silly imho.

Old Pedant
12-08-2012, 11:03 PM
Hey, no fair! That page has *BOTH* the HTML 5 specification *AND* uses JS validation!

What's the point? If you have the JS validation there, you don't need the HTML 5 validation, do you?

Let's strip it back to *JUST* the HTML 5 validation:


<!DOCTYPE html><html>
<head>
<title>html5 form test</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style>
[id]:valid, [id][valid]{ background:#cfc; }
[id]:invalid, [id][invalid] { background:#fcc; outline: 0; box-shadow: none; }
</style>

</head>
<body>
<h1>htm5 form validation test </h1>
<form onsubmit="return false;">
<label for="datedue">
<b>Date Due</b>
<input type="text" name="datedue" id="datedue" placeholder="12/31/2000" title="12/31/2000"
pattern="^[01]*\d{1}[.\/][0123]*\d{1}[.\/]\d{2,4}$"
required autofocus
/>
</label>
</form>

</body>
</html>

And now, indeed, it accepts 13/32/8888 and the field turns a pretty green.

BUT...

But isn't that the fault of the regular expression?!!??

Even a *SMALL* fix to it helps a lot:


pattern="^(0?[1-9|1[012])[.\/](0?[1-9]|[12]\d|3[01])[.\/](19|20)\d\d$"

That will still allow "2/29/2011" and "4/31/1926", but it's a huge improvement.

Give me time and I'll create a regular expression that will only allow correct dates in, say, 1901 through 2099.

rnd me
12-08-2012, 11:08 PM
Terrific, but as I have often said, my customers insist on older browsers being supported. They are not interested in web sites that only work in IE9 or better.

I entered the date 47/89/3012 and it accepted it. :eek:

Shome mishtake, shurely.

I'll stick with my Javaascript.


i appreciated you taking the time to test it and provide feedback.
I've updated the example a bit, integrating your code, while addressing some of the low-hanging UX points raised by our friend.

It's like Captain Planet: "by our powers combined!!!".

I tried to go for a universal (no language) validation routine using your date checker and a upgraded alert routine. You can make it friendlier to natives by using english or french or whatever.
"Day is bad", "dia mal", "jour no bon" (i suck at frech), could provide richer UX at the cost of universality. this is an international starting point.


I think that the js provides a better UX than HTML5 alone. It not much work to integrate both. The default HTML5 error messages can be a bit vague, and it's probably gonna be another 6-12 months before we can default to <input type=date>, (falling-back of course).

I generic-azied your code to accept input fields instead of 3 numbers to reduce typing down the road, and to allow inputs to subscribe with one simple inline event handler.

You can re-use the inform() method instead of alert() on any form using HTML5 syntax, regardless of the native browser support for HTML5 features. The <input> tag is a great place to keep information about the input. Certainly easier to maintain/debug than if it were buried in a <script src> on a CDN'ified production server...

in conclusion, i think it's pretty cool how simple it is to homoginze the alert() and HTML5 validation, and the advantages of a hybrid approach should be self-evident:


tested in IE7-10, FF, CH, OP:


<!DOCTYPE html><html>
<head>
<title>html5 form test</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style>
[id]:valid, [id][valid]{ background:#cfc; }
[id]:invalid, [id][invalid] { background:#fcc; outline: 0; box-shadow: none; }
</style>

</head>
<body>

<h1>htm5 form validation test </h1>
<form onsubmit="return false;">
<label for="datedue">
<b>Date Due</b>
<input type="text" name="datedue" id="datedue" placeholder="12/31/2000" title="12/31/2000"
pattern="^[01]*\d{1}[.\/][0123]*\d{1}[.\/]\d{2,4}$" required autofocus onchange="checkValidDate(this)"
/>
</label>
<input type=submit value=test />
</form>

<script type = "text/javascript">


function inform(inp, message){

if(inp.setCustomValidity){
inp.setCustomValidity(message);
}else{
if(message){
alert(message+ "\n_________________\nex: " + inp.title);
inp.setAttribute("invalid", true);
inp.removeAttribute("valid");
}else{
inp.setAttribute("valid", true);
inp.removeAttribute("invalid");
}
}//end html5/legacy
}//end inform()


function checkValidDate(inp) {
var r=inp.value.split(/\W+/g),
yr= Number(( (r[2]>30?19:20) +''+ r[2] ).slice(-4)) , mmx=r[0], dd=r[1];

if (yr < 1910 || yr > new Date().getFullYear()) {
inform(inp, r.join(" / ") + "\n\n" + " >> "+yr+" <<" );
return false;
}

if (dd<1 || dd>31 || parseInt(dd)!=+dd ) {
inform(inp, r.join(" / ") + "\n\n" + " >> "+dd+" <<" );
return false;
}


mm = mmx - 1; // remember that in Javascript date objects the months are 0-11
var nd = new Date(yr, mm, dd);

var ndmm = nd.getMonth();
if (ndmm != mm) {
inform(inp, r.join(" / ") + "\n\n" + " >> "+mmx+" <<" );
return false;
} else {
inform(inp, "");
}
} /* end checkValidDate() */




</script>

</body>
</html>

AndrewGSW
12-08-2012, 11:29 PM
This is tempting me to ignore (most of) them, use JS, but (of course) rely on server-side validation.
I am not advising anyone to ignore HTML5, I was merely reflecting my own experience. I am happy to adjust my statement to "dont count on them" if it helps :thumbsup:.

What I will continue to do is to apply HTML5 attributes, and test in different browsers. I will probably need to tweak some css. If I'm still not happy with the look and/or behaviour I might remove some of the HTML5 attributes.

Andy.

On reflection, I should have said "some of.." rather than "most of.." :)

AndrewGSW
12-08-2012, 11:40 PM
Still does nothing for me in IE9 if I just click test..

Old Pedant
12-08-2012, 11:41 PM
Here...A complete date validation that works from 1900 to 2099, excepting only that it allows "2/29/1900".

I could even fix that but it's a real pain for such a minor thing.

Test it out.

The regular expression is "exploded" as a comment below the rest of the HTML to make it clearer how it works.

I got rid of the "test" button since it's irrelevant to this code.

Oh...and tested in Chrome, only, so far.
EDIT: Tested in Firefox. Works. Tested in MSIE 9. Doesn't do a thing, as we knew it wouldn't.



<!DOCTYPE html><html>
<head>
<title>html5 form test</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style>
[id]:valid, [id][valid]{ background:#cfc; }
[id]:invalid, [id][invalid] { background:#fcc; outline: 0; box-shadow: none; }
</style>

</head>
<body>
<h1>htm5 form validation test </h1>
<form onsubmit="return false;">
<label for="datedue">
<b>Date Due</b>
<input type="text" name="datedue" id="datedue" placeholder="12/31/2000" title="12/31/2000"
pattern="^(((0?[13578]|1[02])[.\/](0?[1-9]|[12]\d|3[01])|(0?[469]|11)[.\/](0?[1-9]|[12]\d|30))[.\/](19|20)\d\d)|((0?2[.\/](0?[1-9]|1\d|2[0-8])[.\/](19|20)([02468][1235679]|[13579][01345789]))|(0?2[.\/](0?[1-9]|1\d|2[0-9])[.\/](19|20)([02468][048]|[13579][26])))$"
required autofocus
/>
</label>
</form>

</body>
<!--
^
(
(
(0?[13578]|1[02])[.\/](0?[1-9]|[12]\d|3[01])
|
(0?[469]|11)[.\/](0?[1-9]|[12]\d|30)
)
[.\/](19|20)\d\d
)|(
(0?2[.\/](0?[1-9]|1\d|2[0-8])[.\/](19|20)([02468][1235679]|[13579][01345789]))
|
(0?2[.\/](0?[1-9]|1\d|2[0-9])[.\/](19|20)([02468][048]|[13579][26]))
)
)
$
-->
</html>

AndrewGSW
12-08-2012, 11:49 PM
excepting only that it allows "2/29/1900"
in the Excel world that is a valid date :thumbsup:

007julien
12-09-2012, 01:39 AM
Did you see my proposal ? It authorizes 1 1 2013, 01/01/2013, 1 - 1 - 2013 or another New Year 01012013... But 2 29 2013 or 13122014 are forbidden !

Otherwise I am not certain that all the innovations go in the right direction. A few years ago, Ayatollahs of W3C wanted to impose us the XHTML, every profession had to have its DTD, It was really the way of future...
Apparently the reverse gear is on the way with the HTML5 !

Now, its very difficult to reload a page. Let us regret that forms are sometimes stiffer on the web than on the paper. It would be necessary to click outside, on labels, while these should be inside (In particular on the small screens of telephones) !

Then let us wait a little that all this settles... Let us hope only that the best ideas will be adopted !

EDIT : But please allow a date even if there is a unfortunate space before or after !

Philip M
12-09-2012, 12:10 PM
.

Oh...and tested in Chrome, only, so far.
EDIT: Tested in Firefox. Works. Tested in MSIE 9. Doesn't do a thing, as we knew it wouldn't.


So useless, sadly. I do not defend IE, but simply state that something which does not work in IE is not useful.

rnd me's script is fine, but for the life of me I do not see any real advantage over what I regularly use.

Old Pedant
12-09-2012, 10:10 PM
Well, I will point out that my same regular expression could be used in JavaScript to validate the same dates.

Maybe a hacik?


<input type="text" name="datedue" id="datedue" placeholder="12/31/2000" title="12/31/2000"
pattern="^(((0?[13578]|1[02])[.\/](0?[1-9]|[12]\d|3[01])|(0?[469]|11)[.\/](0?[1-9]|[12]\d|30))[.\/](19|20)\d\d)|((0?2[.\/](0?[1-9]|1\d|2[0-8])[.\/](19|20)([02468][1235679]|[13579][01345789]))|(0?2[.\/](0?[1-9]|1\d|2[0-9])[.\/](19|20)([02468][048]|[13579][26])))$"
required autofocus
onchange="this.style.backgroundColor='lime';
if (! (new RegExp(this.getAttribute('pattern'),'i') ).test(this.value) )
{ this.style.backgroundColor='pink';this.focus();}
"
/>

That works in IE, even. <grin/> (Redundant in other browsers, but so what?)

felgall
12-09-2012, 10:33 PM
Well, I will point out that my same regular expression could be used in JavaScript to validate the same dates.

See http://javascriptexample.net/domform12.php for an unobtrusive way to process the pattern attribute in all browsers and not just those that support it without JavaScript.



EZ Archive Ads Plugin for vBulletin Copyright 2006 Computer Help Forum