Javascript date selector in Rails

Many projects I work on require a user to select dates while entering information into a form. Rails makes it trivial to create date selectors and save the results into models via the date_select form helper. Here’s what it looks like by default:

Functional, but hardly friendly to require the user to manipulate three different controls to select a date. Searching the web I found a few different pop-up-calendar JavaScript apps, and settled on using Brian McAllister’s Unobtrusive Date-Picker Widget via Brian landau’s Rails plugin.

I’ve used this successfully for the past year, but noticed this message on the plugin’s home page recently: The latest release of the Unobtrusive Date-Picker Widget JavaScript library makes this plugin unnecessary so I’ve decided to no longer maintain it. Using the date-picker without needing a plug-in sounded great to me! Unfortunately, I couldn’t find any references or instructions on how to use the new (version 5) date-picker with Rails, and there was clearly no built-in support within new new date-picker.

I set out to solve this problem and this is the solution I came up with. The previous plug-in version required changes to my Rails applications’ views in order to activate the date-picker. Reading through the documentation for the new version 5 date-picker JavaScript app, it quickly became obvious that I’d need to handle the date-picker activation completely in JavaScript. This has advantages (the date-picker is truly unobtrusive, since no Rails app changes are needed) and disadvantages (flexibility is lost since the Rails app can’t easily configure the date-picker).

The date-picker needs to bind to the existing date_select form elements in order to function. This example from the documentation demonstrates, with three form elements with DOM IDs of inp1, inp2, and inp3:

[cc lang=”javascript” line_numbers=”false”]
datePickerController.createDatePicker({
formElements:{
// “inp1” represents the day part
“inp1″:”d”,
// “inp2” represents the month part
“inp2″:”m”,
// “inp3” represents the year part
“inp3″:”Y”
}
});
[/cc]

Rails view helpers create form element IDs automatically. For example, a form for a “person” model with a “firstname” input would have an ID of person_firstname. Even though dates are stored as a single field in models, the date_select helper creates three form elements (year, month, and date), which are re-combined when saving to the model. Each of these elements’ IDs are generated as above, but with an identifier (_1i, _2i, or _3i) appended to differentiate the three fields. My first thought was to retrieve the computed IDs in my view code, and pass them to the JavaScript. Looking through the DateHelper source code yielded some promising hints such as the input_id_from_type method, but I eventually gave up as nothing seemed easily accessible from public-facing methods. Instead I decided to rely on Rails’ current convention, and search for the _1i identifier across all form select elements in the page.

[cc lang=”javascript” line_numbers=”false”]
$(document).ready(function() {
// Rails creates date_select ids as
// #{model}_#{attribute}_#{field}i
// where #{field} is a digit representing
// each element in the date/time.
$(“select[id$=’_1i’]”).each(function() {
var id1 = this.id; // e.g. person_birthday_1i
var id2 = this.id.replace(/1i$/, “2i”);
var id3 = this.id.replace(/1i$/, “3i”);
var eles = {};
eles[id1] = “Y”;
eles[id2] = “n”;
eles[id3] = “j”;
datePickerController.createDatePicker({formElements: eles});
});
});
[/cc]

The above snippet from application.js requires jQuery and does the following:

  • Finds all select elements that have an ID ending in _1i. These represent individual date_select instances on the page (in case a page has multiple dates to be selected).
  • For each one, computes the IDs of the three components of the date_select (_1i, _2i, and _3i)
  • Creates a JSON configuration array telling the date-picker which form element describes each part of the date, and in what format. See the Date Formats section of the version 5 date-picker documentation for more details.
  • Instantiates the date-picker

Here’s what the date selection form looks like with the above code in place:

Of course, the magic happens when the user clicks on the calendar icon which now appears to the right of the existing date selection elements:

To get all this working in your project, you’ll of course need to download the date-picker files from Brian McAllister’s site, move the files into your Rails app’s /public directory, and include them with something like the following:

[cc lang=”rails” line_numbers=”false”]


People: <%= controller.action_name %>
<%= stylesheet_link_tag 'scaffold' %>
<%= stylesheet_link_tag '/datepicker/stylesheets/datepicker.css' %>
<%= javascript_include_tag 'http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js' %>
<%= javascript_include_tag '/datepicker/lang/en.js' %>
<%= javascript_include_tag '/datepicker/javascript/datepicker.packed.js' %>
<%= javascript_include_tag 'application.js' %>

[/cc]

One Comment to “Javascript date selector in Rails”