Using jQuery-based Date/Time Picker controls in CakePHP

An overview of your jQuery options, by Mike Panitz

As the summer winds down here in beautiful, increasingly overcast Washington state, I have to face certain facts.  Fact: if I don’t get that stationary trainer set up, I’m not going to ride my bicycle this winter.  Fact: I really, really need a haircut.  Fact: I’m not going to implement the ‘due date’ functionality in my homework hand-in web application by the time school starts again in two weeks.  This last fact is sad, but not tragic, especially since I got other Really Important Stuff done this summer.  And I got figured out how to use jQuery with a calendar sort of control/widget, starting with choosing a date (or time) picker for my web app.

To be clear, my motivation is that I want a a DHTML date/time picker that will make my otherwise plain old input form that much better.  There’s no AJAX involved here, just DHTML interactive goodness.  I’m going to use the jQuery / jQuery UI stuff because it’s easy to use, elegant, and because I’m planning on using it for other things, in the future.  I’ll be continuing to use CakePHP for the backend, since it’s ‘convention over configuration’ approach is refreshingly XML-free, their MVC abstraction is clean, and their ORM implementation is quickly and easily used.

After much fiddling, I’ve decided on one date/time picker control to use.  I’ve also found some strategies for trying this stuff out.  So I’ll start by talking through the strategies, then I’ll talk about the contenders, then finally I’ll call out the winner.  If I have time, I’ll walk you through using the winner in my next post (which will include nitty-gritty details like the exact CakePHP code you’ll need to use :)   )

Suggested strategy for deciding on a UI widget/control:

In general, this seemed to work well:

  1. Find a widget
    This is the ‘Google around for it’ stage.  You’re just looking for options at this point.
  2. Look through the control’s home page, paying special attention to the demo page
    The home page will help make it clear how polished/full-featured the control is.  It should contain a link to a page that contains clear documentation for all the options, and the documentation should contain code samples.  Especially for projects run by individuals, sample code is crucial for figuring out how the author expects you to use it.

    You really, really want to find a ‘demo page’, which shows off the UI widget.  Not only will this let you quickly get a feel for how the widget works, but will serve as a complete, working example for the ‘copy locally’ step (#4, below).

  3. Repeat the above steps until you find something that you like
    ‘Nuff said :)
  4. Copy the demo page into a local directory & make sure it works
    The local directory can either be something in the file system, or something that’s served up by a web server that you’ve got control over.  XAMPP is perfect for this step.

    The real goal here is to make sure that you’ve got everything working, so that when you go to integrate it into CakePHP, you’ve got a working copy to compare your Cake-ified version to.  This is especially useful if you’re making local copies of the various libraries & files that the control depends on.

    This step can also be useful to make sure that you can make the control appear (and behave) the way you want, before investing time to Cake-ify it.

  5. Cake-ify it
    First get the UI part to work, then verify that you can get the data you need back to the server (back to the Cake controller).  Then, and only then, should you fiddle with the control’s options extensively.

Having outlined my suggested strategy for figuring out which control you want, let’s look at the options that I found.  These aren’t the only options, but these are the ones that I found, that seemed to work well.

The Contenders:

Cake’s default date/time picker

Cake_DATETIME_Default
Figure 1: Cake’s default control(s) for a DATETIME field

While not actually jQuery based, I figured that I’d point this out just because of how quick-and-easy this is to program.  It’s built into Cake (obviously), and so you don’t have to do much for this to work.  Just use the FormHelper’s input method on a database field that’s a DATETIME, and Cake takes care of the rest. 

Cake auto-magically provides the user with a collection of drop-down menus that let the user safely pick out the date and time, as shown in Figure #1.

If you’ve got something that doesn’t need to be AJAX-y, this is an option worth considering, simply because of how fast, easy, and reliable it is.

jQuery’s Datepicker

Home Page: http://docs.jquery.com/UI/Datepicker

Demo Page: http://jqueryui.com/demos/datepicker/ 
(there’s another demo in the home page, too)

DatePicker  
Figure 2: The jQuery UI’s Datepicker control

This is the only date/time picker that’s a standard part of the jQuery UI, so it’s easy to get your hands on, easily documented, and you can get CDN-hosting benefits.  The upside of this is that it’s really nicely done – solid documentation, full-featured, and easy to use.  As you can see in Figure 2, above, Datepicker supports the jQuery UI ThemeRoller custom themes, slide-out visual effects, and such nice perks as having the widget ‘output’ a differently formatted string into another form field (in this case it’s outputting "Thursday, 17 December, 2009" into the text input field on the right).  

The major downside is that this control only allows the user to pick the date.  If you want to pick the time as well, you’re on your own – there aren’t any time-picking widgets in the standard jQuery UI.  So the Datepicker widget is a great choice if you’ve got a DATE field in your (MySQL) database, and want the user to have a slick, calendar-based way of picking a date.

A word of warning: You’ll need to watch the format – the default format for the Datepicker isn’t the exact same as the MySQL DATE format, which will cause problems for CakePHP.  You’ll need to use one of the format parameters to make sure that the Datepicker widget puts a properly formatted string into the text field, so that Cake can auto-convert it).

An aside: what if you want to use the Datepicker as part of a solution?

Let’s say that we want the user to be able to pick both the date AND the time.  One option would be to use a separate DATE and TIME field in the database, and have each one nicely tied to a single jQuery widget.  This will make the UI fairly straightforward, but will then complicate later queries.  If we’re interested in determining if the student’s homework submission is late, we’d have to do convoluted queries like "An assignment is be late if it was handed in after the due DATE, or if it was handed in on the due DATE and after the TIME it is due").  Questions like ‘How many days late is the submitted homework’ should be even more fun :)

Luckily , MySQL provides both DATETIME and TIMESTAMP data types – they appear to be pretty much identical (which clearly indicates that I just haven’t researched the differences enough :)   ).  They can be compared directly, and there are PHP routines for dealing with DateTimes (http://us.php.net/manual/en/class.datetime.php), so using a single DATETIME in the database layer, and multiple input fields in the UI layer, seems like a reasonable approach.

The jQuery Datepicker doesn’t do anything with time, but we’ve got a couple of options.  The worst option is to set up the Datepicker’s format string to include an arbitrary, unchanging time (e.g., "12:00:00"), but if we’re going to do that, then why waste the space & effort on recording the time at all? 

If we’re not going to hard-code a time into the field, then we’ll have to ask the user for for the time using a separate widget.  We can do this using two separate widgets in the UI layer.  The question then becomes "Where should I merge those two separate fields into the single DATETIME field?  In JavaScript (on the web page), or in PHP (in the Cake controller method)?"  A friend who’s been doing web programming for a while says that doing such merging work in PHP (in the controller method) is the way to go.  Thinking about it, I agree with him, mostly because using JavaScript to manipulate the automatically generated Cake input form fields seems brittle.  The various arrays (mostly $this->data) in the controller seem much more stable.  For example, the documentation clearly defines the format used, and this definition is so fundamental to how Cake works that it would be a major, breaking change for them to alter it.  An added bonus for putting this ‘merging’ logic into the controller is that the UI can display anything you want, so long as your controller code can parse the fields, then merge and reformat the fields into a single, properly formatted DATETIME string that Cake’s model code is expecting.

So if you’re going to use the jQuery UI’s Datepicker widget to let your users pick the date/time, then you’ll probably want to have a second field that will allow them to pick the time, and then merge these two fields into one DATETIME in the Cake controller method.

timepickr

Home Page: http://haineault.com/media/jquery/ui-timepickr/page/

Demo Page: (at the top of the home page)

timepickr
Figure 3:
The timepickr widget

This widget only picks out the time – there’s no support for picking out the date.  I’m only  mentioning this control at all in case you want to use the approach of providing a Datepicker to pick the date, and something like this timepickr to pick the time.

As you can see in Figure 3, above, the widget is a tad odd.  Essentially, you click on the field ( "{suffix}", in this case), and then the first row of numbers pops out beneath it.  You then choose the hour ("06", in Figure 3) by moving your mouse over it, and the next row pops out.  You then select the minutes ( "30" ), and finally AM/PM (unless you’re using a 24 hour timepickr). 

It’s a really nice interface, actually – not one I would have thought of, but once you use it a couple times, it works really well.

dtpicker

Home Page: http://code.google.com/p/jquery-dtpicker/

Demo Page: http://jquery-dtpicker.vndv.com/

dtpicker

 Figure 4: The dtpicker widget

This is the first combined date and time picker widget that I found.  It’s very similar to the timepickr control, in the sense that you click on the input form (in Figure 4, above, I clicked on the text field under the "event" label), and it displays the first column of choices – the years, in the above figure.  Once you move the mouse over a year, it lets you pick the month ( "March" ), then a range of days ("20-29"), then a specific day ( "22" ), then an hour ( "09:" ), then a minute ( "20 ).  It’s a slick interface, and I liked it.  I could quickly and easily pick out the date and time that I wanted, especially after the timepickr widget familiarized me with how this style of widget worked.

There are two reasons that I didn’t go with with widget.  First, I wanted something that looks like a calendar, since this will be used to pick out due dates for homework assignments.  It’s invaluable to see how far apart dues are, visually, so that it’s clear how much time (a week?  two weeks?) the students will have to work on any given project.  Secondly, this widget doesn’t appear to play nicely with Cake’s CSS ‘out of the box’.

A word of warning: Watch out for the type of the input field that you attach the dtpicker to.  The dtpicker doesn’t appear to work when attached to a text input (e.g., <input type="text">), but instead you must attach it to one of the custom "date" input types that it requires (e.g., <input type="date">)

dyndatetime

Home Page: http://code.google.com/p/dyndatetime/

Demo Page: http://www.mechanicalmarksy.com/hosted/toolman/dyndatetime/example.html

dynDateTime Figure 5: The dyndatetime widget

As you can see in Figure 5, above, the dyndatetime widget looks like a calendar with a space for time at the bottom.  You activate it by clicking on something (in this case, the button labeled ‘PICKER", but you can attach it to the text field instead).  The widget then appears on the screen, and you can pick the time, then pick the date.  The time picker isn’t entirely intuitive (you can SHIFT+Click to increase the hour/minute individually, or you can click-and-hold on the hour (or minute), and then drag the mouse left or right to adjust the time), but once you figure it out, it works pretty well.

The Winner: dynDateTime

dyndatetime, based on the based on Dynarch date time calendar, is what I’m going to use.  It looks pretty slick, seems to work well, and will produce a single field that contains both date and time. 

It seems to be reasonably full-featured, including things like formatting the input field one way, and then formatting another field in a different way.  This will make it easy to have a field that Cake’s server-side code will use to automatically populate the DATETIME database field. 

There’s also a bunch of pre-fab .CSS and language options, too, so you can customize how it looks, or which language you’ll be using it with.  Speaking of which, dyndatetime’s CSS plays pretty well (but not perfectly) with Cake’s default CSS, which is nice.  Generally, there are lots of nice options (http://code.google.com/p/dyndatetime/wiki/Home), and the date/time formatting that can both support MySQL’s DATETIME, and more human-readable formats.

September 12 2009 02:16 pm | CakePHP and jQuery

2 Responses to “Using jQuery-based Date/Time Picker controls in CakePHP”

  1. ezekfred on 16 Oct 2009 at 6:26 am #

    Thank you Mike for this comparison.
    In fact, I’m waiting a stable 1.3 cake version just to keep only jQuery and dynDateTime will be a good choice for our datetime fields.
    Btw, have you write a DynDateTimeHelper like the old DatePickerHelper from
    http://nik.chankov.net/2007/09/13/advanced-datepicker-helper-for-cakephp/
    &
    http://php.abdullahsolutions.com/2008/02/output-helper-javascript-into-headers.html ?

  2. Mike on 16 Oct 2009 at 3:39 pm #

    ezekfred -

    Thanks! I’m glad you found this useful :)

    I have not made a DynDateTimeHelper, sorry. And with school back in full swing, that’s where my time is going now-a-days.

Trackback URI | Comments RSS

Leave a Reply

You must be logged in to post a comment.