Wednesday, July 25, 2012

Patching jQuery Validation for the iOS Date Picker

If you’re trying to use native datepickers with <input type="date"/> in your app and the jQuery Validate plugin for validation, here's something you probably need to know.

I discovered, when testing my app on an iPhone, that the jQuery Validate plugin wasn’t working on my date inputs. It would always mark them invalid. Huh.

I dug into it and found that this is how it determines if a date is valid:

date: function(value, element) {
    return this.optional(element) || !/Invalid|NaN/.test(new Date(value));

That is, it just passes the string to be tested to the Javascript “Date()” constructor and checks to see if something back comes back.

OK…what’s going on then? I logged the value of the input and confirmed that it’s in the sensible ISO format I thought it’d be in:


After an embarassingly large amount of hunting in the wrong places, I eventually uncovered that validation code above and simple ran it:

Tue Jul 17 2012 20:00:00 GMT-0400 (Eastern Daylight Time) 

OK, so that makes sense in Chrome—the validation works in Chrome. So I ran that in iOS and…it failed! Here’s my commit message after I figured this out:

// patch the validate "date" method to accomodate iOS-style ISO dates
// because some browsers (including Chrome 19+ and iOS) support HTML5 date
// inputs, but some of those same browsers' Date() implementation
// doesn't parse them... WUT?! I'm looking at you iOS

This is madness. iOS 5’s Date() can’t parse what has got to be the easiest to parse date string ever.

Enough grumbling…what do we do? My first solution involved using the other date parse rule in the Validate plugin:

dateISO: function(value, element) {
    return this.optional(element) || /^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}$/.test(value);

That worked, since it just matches a simple yyyy-MM-dd pattern. I (of course) do server side validation, too, so I’m not worried about a user entering a syntactically correct, but practically incorrect date like 2012-02-30.

Rather than change all my inputs to use this alternative rule, or mess with my validation routine (I’m using the unobtrusive flavor)—I’d really like to just leave all that be, I decided to patch the first validator like so:

if ($.validator) {
    var originalDateValidator1 = $;
    var originalDateValidator2 = $.validator.methods.dateISO;

    $ = function (value, element) {
        var isValidDate =
            originalDateValidator1.apply(this, arguments) ||
            originalDateValidator2.apply(this, arguments);

        return isValidDate;

Quite simply, this just runs both of the date checkers and returns true if either of them pass.

In addition to not having to actually change any of my HTML, this code sits outside the library itself (it’s in my global.js file) so I can still update my plugins or load them from CDNs without fear. Oh, and if a user enters a date in the usual MM/dd/yyyy format in a browser that doesn’t support the native datepicker, the validation will still pass.

Hopefully Apple fixes this issue…


Kikoanis said...

Thank you, you saved my day

Kikoanis said...
This comment has been removed by the author.
Anonymous said...

Hey buddy,

you definitly made my day!!!!

Thanks a lot!


Mike Causer said...

Brilliant, thanks

Unknown said...

I've been having issue where the validation plugin won't validate a date input type that is set to required, on iPad only. Even after the date is selected from the native iOS datepicker, the plugin still marks the input with an error and says it is required.

Brian Watts said...

This saved my bacon. (Along with a tip from stackoverflow to disable my jquery UI timepicker on iOS by using a line of modernizr code)

Thanks, Man!

Taibai Li said...

qihang0611coach outlet store online
pandora jewelry
michael kors outlet
oakley sunglasses
coach factory outlet
christian louboutin sale
coach outlet
true religion jeans
toms shoes
nike air max
chanel online shop
ralph lauren
ray ban sunglass
polo ralph lauren
tory burch outlet
burberry outlet online
gucci outlet online
ray ban uk
kate spade uk
cheap ray ban sunglasses
ray ban glasses
cheap jordans
coach outlet
true religion
toms outlet
michael kors bags
michael kors outlet online
coach outlet online
michael kors bag

Klaas Leussink said...

Saved my day, thanks!!

mao qiuyun said...

juicy couture outlet
soccer jerseys
ralph lauren outlet
hermes bags,
christian louboutin outlet
louis vuitton bags,
louis vuitton handbags
cheap nfl jerseys,
fitflop shoes
ugg boots,
oakley sunglasses wholesale,
michael kors uk
michael kors outlet
the north face clearance
manchester united jersey
iphone 6 cases
michael kors uk
rolex watches
coach outlet store,
giuseppe zanotti outlet
converse all star
air max 2015
mcm handbags
michael kors factory outlet,
michael kors factory outlet,
cheap soccer jerseys
true religion jeans,
tory burch shoes
hermes birkin
coach outlet
tory burch outlet online
oakley sunglasses