Skip to main content

Grails - replacing g:datepicker with gui:datepicker

A typical datepicker code that is generated for your domain classes is shown below:

<g:datepicker name="dateOfJoin" value="${objInstance?.dateOfJoin}"
/>


Note: This code is autogenerated when you choose to create Controllers and Views by running the grails command "generate-all" for any domain class.

It displays the Date, Month, year drop downs. Also it shows Drop downs to select Hrs and Mins.



To remove the Hr and Mins dropdown a "precision" attribute should be used.

<g:datepicker name="dateOfJoin" value="${obj?.dateOfJoin}"
precision="day"/>




To enable Null dates in your domain object



The default datepicker options do not allow to choose a blank date.

By adding noSelection and default attributes as shown we can acheive the desired result.


<g:datepicker name="dateOfJoin" value="${objInstance?.dateOfJoin}"
default="none" noSelection="['':'-Choose-']"/>




More customization - Displaying fixed number of years in the dropdown box.



One more useful feature is customizing the years displayed in the years dropdown. By default this field displays +/- 100 years.

<g:datepicker name="dateOfJoin" value="${objInstance?.dateOfJoin}"
default="none" noSelection="['':'-Choose-']" years="${2005..2015}"/>

In case you donot want to hard code the years but dynamically generate the years from current year till next 5 years, we need to add the following.

<g:datepicker name="dateOfJoin" value="${objInstance?.dateOfJoin}"
default="none" noSelection="['':'-Choose-']" years="${(1900 + (new Date().year))..(1900+ (new Date() + (5 * 365)).year)}"/>

You could also choose to use Calendar class to get more accurate number of years and to avoid the logic of adding 1900 to the year.

Is it worth the effort when so much customization is needed.



A better alternative is to use the datepickers available from number of plugins available on grails plugin portal.

Remainder of this post is about the gui:datepicker from Grails plugin grails-ui


To start with we need to install grail-ui plugin.
Add the following to your head tag of the "create.gsp" or "edit.gsp" of the corresponding domain class you are working with.

<gui:resources components="['datePicker']"/>

Add class="yui-sam-skin" to the body tag of the page where you want to include the datepicker. It can also be added to the div tag that is sorrounding your form.

Replacing previous example with the following will give us editable textfield and a small calendar icon.

<gui:datePicker name="dateOfJoin" id="dateOfJoin" value="${objInstance?.dateOfJoin}">

It is important to put the id field same as your field in the domain class.



Additionally you can apply formatting to the date by using formatString attribute.
add formatString = "dd/MM/yyyy" to the tag.

Issues with gui:datepicker


When we try to save the data "Controller" object is unable to convert the parameter to the Date object. We need to apply a pre-processing logic before the "save" action is performed on the controller.

Add the following code to your controller. Note that format you used in datepicker should match the parse string that we are using.

def beforeInterceptor =
[ action:
{
params.dateOfJoin = params.dateOfJoin?Date.parse("dd/MM/yyyy", params.dateOfJoin):null


},
only:['save']
]
In case no date is selected dateOfJoin is set to null. The interceptor can be extended to another action by changing it to

def beforeInterceptor =
[ action:
{
params.dateOfJoin = params.dateOfJoin?Date.parse("dd/MM/yyyy", params.dateOfJoin):null


},
only:['save','update']
]

Caution: the date field should be declared to accept null values. In the domain class add the following
static constraints = {
dateOfJoin(nullable:true)
}

Comments

Popular posts from this blog

Grails - cross-field Date validation

Often we run into domain classes with date fields. If the domain class has two datefields, startDate and endDate, and the rule for a valid combination is "endDate to be greater than startDate", how do we handle? I listed below two of the options, either using domain level constraints or using the domain classes. Option 1: Using domain constraints. Let us take a sample Grails Domain class class Student{ String name String school Date startDate Date endDate } Add the following constraints to enforce validation rules where name, school, startDate cannot be blank and endDate if present should be greater than startDate.

Grails - Querying complex associations

Criteria class allows performing complex searches on grails objects. There are number of shortcut methods for performing queries but these methods have limitations in terms of number of conditions used in "where clauses". Traditional sql "joins" are not possible as shown in some of the Grails "Finder" methods shown below. Sample 1: def list = AccountTransaction.findAllByCompanyCodeAndVoucherDateBetween(branch, fromDate, toDate, params) Sample 2: def list = AccountTransaction.findAllByCompanyCodeAndVoucherDateGreaterThanEquals(branch, fromDate, params) Sample 3: def list = AccountTransaction.findAllByCompanyCodeAndTransGroup(branch, group, params) "params" contains attributes related to sorting, paging etc. It is very easy to use finder methods but when you want to filter objects by more conditions we need to look for alternatives. For understanding the relationships used in this sample, I listed the grails domain classes. class TransactionTyp

Implementing advanced sort in Grails

The "list" pages generated by inbuilt scaffolding/template features of grails have pagination and sorting features. However, if the domain object displayed in the list is a nested object having another domain object as a property, you may notice that sort is not enabled for that field. Boiler plate code for the header of the list is shown below. As you would have noticed few columns have sortable columns automatically generated by Grails command, generate-all or generate-views. The properties 'partyAccount' and 'bankAccount' in this sample are domain classes nested in the domain class 'partyTransaction'. We could convert them to sortable columns by using the tag g:sortableColum