Binding jQuery UI Datepicker to Grails Domain

In this post I am going to show you how you can write a custom tag to use the JQuery UI datepicker instead of the <g:datePicker> tag provided by Grails out of the box.

How <g:datePicker> tag works

When you have a Date field in your Grails domain class and have generated the default views for that domain you will notice that the date field(s) will be defaulted to three drop down boxes (year, month, day). Upon submit four request parameters will be sent as part of the <g:datePicker> tag. Say that our date field in our domain is declared as orderDate. The request parameters associated with that request would have the following naming convention:

orderDate
orderDate_day
orderDate_month
orderDate_year

All these parameters are necessary for grails to do the appropriate binding to the orderDate field and to successfully save to the database.

What if I do not want to use Grails default date picker?

While this is good, since Grails provided it for free without writing a single line of code, it is not very efficient for the end user to have to select three drop downs. I usually use the JQuery UI framework a lot in my Grails and Spring apps for widgets and DOM Scripting. Do as follows:

  1. Download your favorite Jquery theme.
  2. Unpack it, look at the demos (Specially at the path structure for js, css, and themes)
  3. Bring that into your Grails web-app folder
    1. Copy the themes folder from the download straight out of web-app folder.
    2. Create a jquery folder under js.
    3. Put jquery-1.4.4.min.js under jquery folder created in previous step.
    4. Copy the ui folder from the download to the jquery folder created in step 2.

That should give you the proper setup for you to start adding jQuery and jQuery UI components to your application.

Next I will show how to bind a Jquery date picker to a grails date field in a domain class in two different ways. They are as follows:

  1. Without writing a Grails custom tag
  2. Writing a Grails custom tag

Using Jquery date picker without using Grails custom tags

Step 1: Enter the following in head of your create.gsp

<head> code

Step 2: Replace the g:datePicker tag with

          

Step 3: Create the following Javascript file coche.js. This is responsible for populating the hidden fields once a date has been selected. The code is as follows:

$(document).ready(function() {

  $( "#orderDate" ).datepicker({
      onClose: function(dateText, inst) {
        $("#orderDate_month").attr("value",new Date(dateText).getMonth() +1);
        $("#orderDate_day").attr("value",new Date(dateText).getDate());
        $("#orderDate_year").attr("value",new Date(dateText).getFullYear());
      }
  });
});

Step 4: Run your grails application go to the create.gsp select a date through the calendar and click on create. You should have your custom orderDate field successfully binded in the domain orderDate field just like if you would have used the default <g:datePicker> grails tag.

A jQuery Date Picker Grails Custom Tag

There is nothing wrong with the first approach but it has a couple of disadvantages:

  1. For every jquery date picker that I want to add to the form I have to remember to add three extra hidden input fields with the naming convention dateDomainFieldName_year, dateDomainFieldName_month, dateDomainFieldName_day.
  2. For every jquery date picker field that I have in a single page I will have to add about 8 lines of code of Javascript to populate the hidden fields once a date has been selected.

So my goal is to write a Grails Custom tag that will be responsible for doing the two things above. Additionally it will work for as many date fields you want in your form.

Step 1: Create a Grails Tag Lib as folllows:

Grails tag for jQuery date picker ui widget

Step 2: Replace your input orderDate and associated hidden fields for this:

Step 3: Delete the coche.js

Step 4: Remove the coche.js reference from the head tag in your create.gsp

You should be able to add many jQuery calendars without having to do DOM scripting to populate hidden fields as the custom tag is already doing it for you.

Conclusions

The grails tag for the jQuery UI date picker widget has the advantages as follows

  1. It creates three hidden input fields dateField_day, dateField_month, dateField_year.
  2. It’s responsible for populating these hidden input fields when a date has been selected from the calendar.
  3. Supports having multiple date fields in the same form without any conflict.

The Code

The code can be found at this github repository https://github.com/dariopardo/JQueryDatePickerGrailsTag

21 thoughts on “Binding jQuery UI Datepicker to Grails Domain

  1. SpotLight

    It’s very exiting to find this http://www.dariopardo.com blog.
    Oh, this was a really quality post. In theory I’d like to write like this too – taking time and real effort to make a good article… but what can I say… I prolong alot and never seem to get something done.

    Reply
  2. Sérgio M.

    Hi! Great solution but when we post the data and the save method fails with validation then the field don’t store the value.

    Reply
  3. Dario Pardo Post author

    Hola Sergio,
    Acabo de crear un repositorio en github donde he puesto una aplicacion Grails ilustrando el jqueryDatePickerTagLib. Puedes bajarte el codigo en https://github.com/dariopardo/JQueryDatePickerGrailsTag
    Pon especial atencion en los siquientes ficheros:
    create.gsp en grails-app/views/datesTest
    main.gsp en layouts (solo una entrada de css)
    jqueryDatePickerTagLib en taglib
    y luego el jQuery framework en web-app/js
    y los themes en web-app/themes

    Dejame saber si todavia no te funciona despues de probar el ejemplo.

    Hi all I have just created a github repository with an illustration of the post above. Pay special attention to the following files:
    grails-app/datestTest/create.gsp
    layouts/main.gsp (a css entry only)
    grails-app/taglib/jqueryDatePickerTagLib

    put jquery under
    web-app/js

    put jquery themes under
    web-app/themes

    Let me know if you have any further questions

    Reply
  4. Tom Romano

    hope you dont mind if I link to your post from my blog. It’s exactly what I was working on and It’s very informative and well done. Much appreciated. Keep up good work.

    Reply
  5. Pingback: Binding DatePicker with jQueryUI and Grails

  6. Ben

    Thanks for this! I ended up adding a few extra features to allow me to show the month and year selectors on the calendar, as well as specify the year range. Also, I added the population of the current value back into the field. Here’s the class:

    class JqueryDatePickerTagLib {

    def jqDatePicker = {attrs, body ->
    def out = out
    def name = attrs.name // The name attribute is required for the tag to work seamlessly with grails
    def id = attrs.id ?: name
    def minDate = attrs.minDate
    def showDay = attrs.showDay
    def value = attrs.value
    def changeMonth = attrs.changeMonth
    def changeYear = attrs.changeYear
    def yearRange = attrs.yearRange
    def yearsBack = attrs.yearsBack
    def yearsAhead = attrs.yearsAhead

    def dateString = value ? value.format(‘MM/dd/yyyy’) : “”
    def dayString = value ? value.format(‘dd’) : “”
    def monthString = value ? value.format(‘MM’) : “”
    def yearString = value ? value.format(‘yyyy’) : “”

    // Create date text field and supporting hidden text fields need by grails
    out.println “”
    out.println “”
    out.println “”
    out.println “”

    // Code to parse selected date into hidden fields required by grails
    out.println ” \$(document).ready(function(){”
    out.println “\$(\”#${name}\”).datepicker({”
    out.println “onClose: function(dateText, inst) {”
    out.println “\$(\”#${name}_month\”).attr(\”value\”,new Date(dateText).getMonth() +1);”
    out.println “\$(\”#${name}_day\”).attr(\”value\”,new Date(dateText).getDate());”
    out.println “\$(\”#${name}_year\”).attr(\”value\”,new Date(dateText).getFullYear());”
    out.println “}”

    // If you want to customize using the jQuery UI events add an if block an attribute as follows
    if(null != minDate){
    out.println “,”
    out.println “minDate: ${minDate}”
    }

    if(showDay != null){
    out.println “,”
    out.println “beforeShowDay: function(date){”
    out.println “var day = date.getDay();”
    out.println “return [day == ${showDay},\"\"];”
    out.println “}”
    }

    if(changeMonth != null) {
    out.println “,”
    out.println “changeMonth: ${changeMonth}”
    }

    if(changeYear != null) {
    out.println “,”
    out.println “changeYear: ${changeYear}”
    }

    if(yearRange != null) {
    out.println “,”
    out.println “yearRange: ${yearRange}”
    }

    if(yearsBack != null && yearsAhead != null) {
    def thisYear = Calendar.getInstance().get(Calendar.YEAR)
    def minYear = thisYear – yearsBack.toInteger()
    def maxYear = thisYear + yearsAhead.toInteger()
    out.println “,”
    out.println “yearRange: ‘${minYear}:${maxYear}'”
    }

    out.println “});”
    out.println “})”
    }
    }

    Then in my gsp, my tag looks like this:

    Reply
  7. Ben

    OK, WordPress mangled my code. I’ll try again…

    The class:

    class JqueryDatePickerTagLib {

    def jqDatePicker = {attrs, body ->
    def out = out
    def name = attrs.name // The name attribute is required for the tag to work seamlessly with grails
    def id = attrs.id ?: name
    def minDate = attrs.minDate
    def showDay = attrs.showDay
    def value = attrs.value
    def changeMonth = attrs.changeMonth
    def changeYear = attrs.changeYear
    def yearRange = attrs.yearRange
    def yearsBack = attrs.yearsBack
    def yearsAhead = attrs.yearsAhead

    def dateString = value ? value.format('MM/dd/yyyy') : ""
    def dayString = value ? value.format('dd') : ""
    def monthString = value ? value.format('MM') : ""
    def yearString = value ? value.format('yyyy') : ""

    // Create date text field and supporting hidden text fields need by grails
    out.println ""
    out.println ""
    out.println ""
    out.println ""

    // Code to parse selected date into hidden fields required by grails
    out.println " \$(document).ready(function(){"
    out.println "\$(\"#${name}\").datepicker({"
    out.println "onClose: function(dateText, inst) {"
    out.println "\$(\"#${name}_month\").attr(\"value\",new Date(dateText).getMonth() +1);"
    out.println "\$(\"#${name}_day\").attr(\"value\",new Date(dateText).getDate());"
    out.println "\$(\"#${name}_year\").attr(\"value\",new Date(dateText).getFullYear());"
    out.println "}"

    // If you want to customize using the jQuery UI events add an if block an attribute as follows
    if(null != minDate){
    out.println ","
    out.println "minDate: ${minDate}"
    }

    if(showDay != null){
    out.println ","
    out.println "beforeShowDay: function(date){"
    out.println "var day = date.getDay();"
    out.println "return [day == ${showDay},\"\"];"
    out.println "}"
    }

    if(changeMonth != null) {
    out.println ","
    out.println "changeMonth: ${changeMonth}"
    }

    if(changeYear != null) {
    out.println ","
    out.println "changeYear: ${changeYear}"
    }

    if(yearRange != null) {
    out.println ","
    out.println "yearRange: ${yearRange}"
    }

    if(yearsBack != null && yearsAhead != null) {
    def thisYear = Calendar.getInstance().get(Calendar.YEAR)
    def minYear = thisYear - yearsBack.toInteger()
    def maxYear = thisYear + yearsAhead.toInteger()
    out.println ","
    out.println "yearRange: '${minYear}:${maxYear}'"
    }

    out.println "});"
    out.println "})"
    }
    }

    The tag:

    Reply
  8. Pingback: domain name

  9. Pingback: Automated indexing

    1. Dario Pardo Post author

      Hi Simone,
      Sorry for the late response, I have not tried Grails 2.0 yet, busy with other stuff. I would suspect it does as long as to bind a date in a gsp to a date in the domain they still require the following fields:
      dateFieldName (date field name)
      dateFieldName_day
      dateFieldName_month
      dateFieldName_year
      You can verify that by creating a date field using grails out of the box and put a println statement in the controller to see all the date related fields. I would also do a view generated source with Firefox developer toolbar to see what markup the grails tag is generating. In essence that’s what I was trying to show with the post (The intent was to use a tag so that it writes all that markup for me, rather than typing it myself for as many date fields i have).

      Reply
  10. Tom

    Greetings!

    This DatePicker works fine, but I was missing the “required” flag, in order to get grails to validate the form prior sending it.

    Therefore I enhanced your Tag a bit.

    First, enhance the Tag to accept the “mandatory” flag, this is done by adding/modifying these lines:

    def mandatory = (attrs.mandatory)? 'required=""' : ""
    //Create date text field and supporting hidden text fields need by grails
    out.println ""

    Now, the tag may be written/ enhanced like this:

    Hope this helps and thanks for this nice piece of code :)

    BTW: @Simone: I have successfully deployed this custom-tag inside a grails 2.0.1 application, so: Yes, it works with Grails 2 aswell :)

    Cheers,

    Tom

    Reply
  11. Tom

    oh, bad luck, it messed up the code.

    Here it is again:

    add/modify these lines:
    def mandatory = (attrs.mandatory)? ‘required=””‘ : “”
    Create date text field and supporting hidden text fields need by grails
    out.println “”

    then enhance the g-Tag:

    Cheers

    Reply
  12. Jason

    Just wanted to point out an alternative approach that supports users typing the formatted date directly into the field in addition to using the JQuery date picker.
    You can register a custom PropertyEditor for Date properties that can take care of the conversion to/from String values. There are lots of examples of doing this, including here.

    Reply
    1. Ian

      Sorry, I forget to put a \ berfoe ${resource(…)} in my sample. The template files are not GSP files themselves, but are Groovy template engine files. The $ sign is a reserved symbol (the template engine will try to resolve the statement in a ${…} block), so to put it literally in our template we must escape it with \.

      Reply
  13. http://Www.chipdesignjobs.com/blog/view/115143/sports-activities-marketing-in-the-age-of-social-media

    If Facebook customers genuinely only have two-way conversations with a tiny number of real mates, what do we make
    of the fact that a brand like the Ford Motor Firm
    has 205,654 folks who ‘Like’ the brand? And there are no responses whatsoever from
    anybody at Ford. Some ‘friend’ facebook likes appear twice (http://Www.chipdesignjobs.com/blog/view/115143/sports-activities-marketing-in-the-age-of-social-media)

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Notify me of followup comments via e-mail. You can also subscribe without commenting.