Thursday, 18 December 2008

grails + ajax: chained selects

From time to time, I run into the following problem. A User has to fill in a form containing 2 drop down lists, and I need to populate the second one with options that depend on the selection made on the first select box. This problem, commonly known as 'Chained Selects' can be easily solved using a dusting of ajax magic.

The principle behind the solution is reasonably straightforward and involves attaching a listener to an HTML element such as a select field. This listener detects events triggered when a User moves the mouse, clicks on an element, etc. In our case, we're interested in the event when the User makes a selection. The listener will then fire a javascript function to perform an ajax call to the server. This call will inform the server as to the selection made on the first select element. Based on this information, the Server will create an HTML snippet containing the second select element and populate it with the correct set of options. This snippet is then sent back as a response to the ajax function, which updates the page accordingly.

To demonstrate this feature, I'm using a simple example containing 2 domain classes, Family and Member. These are listed below,


class Family{

String surname

String description

static hasMany = [members : Member]

static constraints = {
surname(blank:false)
description(blank:false)
members(nullable:true)
}


String toString()
{
return surname
}

}



and,


class Member{
 
String firstName

String lastName

String username

static belongsTo = Family

Family family

static constraints = {
firstName(blank:false)
lastName(blank:false)
username(blank:false)
family(nullable:true)
}

String toString()
{
return lastName + ", " + firstName
}
}




The example revolves around 2 drop down lists. The first of these lists families, e.g. Simpsons and Griffins [Family Guy]. Now I want the second drop down list to be correctly populated with the family members depending on the selection made to the first drop down list.

Step 1: Import 'prototype'

We're going to use prototype to implement this feature. Note you're not restricted to using this library. Others such as jQuery will do an equally impressive job. So the first step is to import in the library as follows,

<g:javascript library="prototype"/>





Step 2: Implement 2 drop down lists

Next we need to implement the 2 select elements as so,

<td>
<label for="family">Family:</label>
</td>
<td>          
<g:select id="familySelect" from="${Family.list().surname}" name="familySelected" value="">
</g:select>
</td>

<td valign="top" class="name">
<label for="member">Member:</label>
</td>


<td>
<div id="memberSelect">
<g:select from="${Member.list()}" name="memberSelected" value="">
</g:select>
</div>
</td>





Step 3: Hook up the ajax code

<g:javascript>
document.observe('dom:loaded', function() {
$("familySelect").observe("change", respondToSelect);
});


function respondToSelect(event)
{
new Ajax.Updater("memberSelect",
"/chainedSelect/family/updateSelect",
{method:'get', parameters: {selectedValue : $F("familySelect")} }
);
}

</g:javascript>



Here we do a couple of things; first of all we attach a listener to the 'familySelect' element to detect for any 'change' events fired when a User makes a selection on this element. Secondly we implement the ajax function that will be triggered when such an event is detected. In this instance we're using prototype's Ajax.Updater() function, which takes a number of arguments that are fully documented elsewhere. The first argument is the id of the element that will be updated by the response to the ajax function. In our case this will be a second drop down list. The second argument is a url pointing to a grails action to service our ajax request. Finally we have a set of optional parameters, the important one being 'selectedValue' which will hold the selection made by the User on the first drop down list.

Step 4: Write the grails action


def updateSelect = {
     def familySelected = Family.find("from Family as family where family.surname=:surname", [surname:params.selectedValue])

render (template:"selectMember", model : ['familySelected' : familySelected])

}




This the grails action that will service the ajax call. Quite simple really. It takes the value selected from the Family dropdown list and uses it to retrieve the corresponding Domain object. This object is then supplied to a tempate file that is subsequently returned as a response to the ajax function in step 3.

Step 5: Write the HTML to update the page.

<g:select
      from="${familySelected.members}"
name="memberSelected" value="">
</g:select>



This is the HTML that will be used to update the page by the ajax function defined above. Note that since I'm using templates, I need to save this in a file whose name should be prefixed with an underscore, '_'.


And here is the final result.
When we select 'Simpsons' as the Family, the second drop down is correctly populated with the members of the Simpson family.



Conversely, if we select 'Griffin' as the family, the second drop down list is populated with the members of the Griffin family.

As a final note, this example could be improved by displaying a default set of values for both selects, when the page is first loaded.

You can download the code [chainSelectFamily.zip] from here.

Monday, 15 December 2008

grails: Implementing Search [2]

In a previous post, I described a quick start approach to using the Searchable Plugin. This approach relied on the controller and view supplied with the plugin and is useful for prototyping and testing. However it's not the ideal way to implement search using the plugin.

In this post, I demonstrate how you can customise the Searchable plugin by developing your own controller and views.

The Searchable plugin provides us with 2 distinct ways to search the properties of domain classes. The first of these is the dynamic 'search' method

DomainClass.search(String query)



which is attached to Domain classes that have the static property 'Searchable' defined within them. This restricts the search to only the properties of the Domain Class.

Secondly the plugin provides the SearchableService class,

searchableService.search(String query)



which enables us to search properties across a set of Domain classes. The documentation here provides further details for both approaches.

Step 1-3: Setup

Repeat Steps 1,2 & 3 from the previous post.

I'm using a different example for this post to better demonstrate the similarities and differences between the 2 search mechanisms. This example consists of 2 domain classes listed below and whose purpose is self-explanatory,


class Film{
    String actor

String title

String releaseDate

static Searchable = true

static constraints = {
actor()
title()
releaseDate()
}

}




and,


class Music{
    String artist

String title

String releaseDate


static Searchable = true

static constraints = {
artist()
title()
releaseDate()
}


}



I've implemented step 3 slightly differently. Instead of 1 text-field, we now have the following,

<g:form url='[controller: "customSearch", action: "searchMusic"]' id="searchMusic" name="searchMusic" method="get">
<g:textField name="query" value="${params.query}" size="10"/> <input type="submit" value="Search Music" />
</g:form>

<g:form url='[controller: "customSearch", action: "searchFilm"]' id="searchFilm" name="searchFilm" method="get">
<g:textField name="query" value="${params.query}" size="10"/> <input type="submit" value="Search Film" />
</g:form>


<g:form url='[controller: "customSearch", action: "searchAll"]' id="searchAll" name="searchAll" method="get">
<g:textField name="query" value="${params.query}" size="10"/> <input type="submit" value="Search All" />
</g:form>


Which look like,



These text-fields, allow the User to search individually for Music or Film or indeed collectively across both categories.

Step 4: Implement the Controller

Next, we build our custom search controller, containing actions that will service the text-fields defined in the forms above.


import org.compass.core.engine.SearchEngineQueryParseException

class CustomSearchController{

def searchableService

def searchMusic = {

if(params.query?.trim())
{

def searchResults = Music.search(params.query)

def total = searchResults.total

def list = searchResults.results

return [totalResults: total, list:list, type:"music"]
}
else
{
return [:]
}

}


def searchFilm = {

if(params.query?.trim())
{

def searchResults = Film.search(params.query)

def total = searchResults.total

def list = searchResults.results

return [totalResults:total, list:list, type:"film"]
}
else
{
return [:]
}

}


def searchAll = {

if(!params.max) params.max = 5
if(!params.offset) params.offset = 0

if(params.query?.trim())
{
try
{

def searchResult = searchableService.search(params.query, params)

def total = searchResult.total

def list = searchResult.results

return [totalResults:total, list:list, type:"all"]
}
catch (SearchEngineQueryParseException ex)
{
return [parseException: true]
}
}
else
{
return [:]
}

}

}



At the top of the code, we inject in the plugins' SearchService class. Next we declare the actions required to service the search textfields defined in step 3. The first 2 actions implement search using the dynamic method, whereas the 'searchAll' action uses the SearchableService class mechanism. Both approaches return a 'searchResult' object which contains a number of results data documented here. For our purposes, we're only interested in the search results and their count.

I'm not going to list the view pages here as they're typical gsp pages and don't add any value to the current discussion. However if you're interested, the full code is available [compass2.zip] for download here.

The following images show the results from performing individual and collective searches.

This one shows a 'Music' only search, when I enter a value of 'Will Smith' into the 'search Music' textfield.




This one shows a 'Film' only search, when I enter a value of 'Will Smith' into the 'search Film' textfield.



And finally a collective search, where I enter the value 'Will Smith' into the 'searchAll' text-field.



As expected the plugin returns Music and Films associated with the artist/actor, Will Smith.

The complete code for this example [compass2.zip] is available here.

ps - I noticed something peculiar with Searchable plugin, when using the test data that I generate in the bootstrap class. If I perform a query on 'Will', it returns nothing. Yet if I enter a value of 'Will Smith', then the search returns the correct results. However if I repeat this for 'Mark' and 'Mark Wahlberg', I get identical results, i.e. I get back, Music/Film or both depending on the search type.

Friday, 12 December 2008

grails: ajax powered validation [Update]

In a previous post, I outlined a method to perform textfield validation using jQuery. However a recent comment by Jan correctly pointed out a simpler method using grails' own ajax tag, <g:remoteField>.

So to implement this feature in a simpler way do the following,

Step 1: Import scriptaculous

<g:javascript library="scriptaculous"/>







Step 2: Code up the textfield and message div


<g:remoteField controller="member" action="validateUsername" paramName="username" name="username"

update="messageDiv" value="${fieldValue(bean:member,field:'username')}">

</g:remoteField>
<div id="messageDiv" style="color:blue"></div>






The message div will be populated with the ajax response, i.e. the uniqueness validation result.

Step 3: Code up the grails action


def validateUsername = {
        def message = ""

def inUse = ["homer", "marge", "bart", "maggie", "lisa"]

if (params.username)
{
if(inUse.contains(params.username))
{
message = "The username has already been taken. Please enter a different one"
}
else
{
message = "Username Ok !...."
}
}

render message

}




Not much change here other than the response messages.

And that's it.

Thursday, 11 December 2008

grails: ajax powered validation

[The contents of this post have been superseded by this post]

I'm not keen on filling in forms, especially ones which are badly designed. To give you an idea of what I'm talking about, consider the typical registration form as shown.

Here the User is expected to provide many personal details in addition to a username which must be unique. The catch is that the user won't know whether the value they have entered is unique until the form has been submitted.

If the username is already in use, the form is redisplayed and the User is asked to provide an alternative.

Now one could envisage situations where the User
has many attempts at providing a valid username until they are successful. This would result in a number of redundant form submissions, page refreshes and clearly a frustrating experience for the User.

One way to address this shortcoming, is to use ajax to perform a validation check. Specifically, once a User has entered a value into the textfield, an ajax call is made to the server requesting that the textfield content be validated. The server performs the check and returns a response which will be used to generate a message informing the User about the validity of the data they have just entered. This approach overcomes the need to perform pointless form submissions and page regeneration.

To demonstrate how to implement this, I've developed a contrived example using jQuery's excellent support for ajax functionality.

Step 1: Download & Import jQuery

In this step you need to download jQuery and place it in the web-app/js folder.
Next you need to import it into the gsp page by placing the following statement between the <head> tags, e.g.

<g:javascript library="jquery-1.2.6.min"/>





Step 2: Setup the Textfield for validation.

Next we need to set up the textfield for validation. In this example I'm going to validate usernames.

<tr class="prop">
     <td valign="top" class="name">
<label for="username">Create Username:</label>
</td>

<td valign="top" class="value ${hasErrors(bean:member,field:'username','errors')}">
<input type="text" id="username" name="username" value="${fieldValue(bean:member,field:'username')}"/>
<div id="usernameMessageOk" style="color:green">Username Ok !....</div>
<div id="usernameMessageFail" style="color:red">Please try again... That username is already in use</div>
</td>

</tr>




Nothing difficult here. The only modifications I've made to the code generated by scaffolding is to add 2 extra divs which will be used to inform the User about the success/failure of the validation. Note these divs are hidden by default as shown in the next section.

Step 3: Hook up the ajax call

In this step we set up jQuery's ajax function to perform the validation


<g:javascript>
    var $j = jQuery.noConflict();

$j(document).ready( function()
{
$j('#usernameMessageOk').hide()
$j("#usernameMessageFail").hide()

$j("#username").change(function()
{
var name=this.value

$j.ajax({
url: "/ajax_validation/member/validateUsername",
dataType: "text",
data: "username=" + this.value,
cache: false,
success:function(text)
{
if(text == 'ok')
{
$j('#usernameMessageOk').show();
$j("#usernameMessageFail").hide()
$j("#username").css({'background-color': 'yellow', 'color':'black' });
}
else
{
$j("#usernameMessageFail").show();
$j('#usernameMessageOk').hide()
$j("#username").css({'background-color': 'red', 'color':'white' , 'border':'solid 1px #0000ff'});
}
}

});

});

});
</g:javascript>








There's quite a few things going on in this snippet. Firstly we hide the message div's using jQuery. Next we bind the username text-field to jQuery's .ajax() function. This will fire whenever the User moves focus away from the textfield e.g. by clicking elsewhere or hitting the 'tab' key.

The ajax function makes a call to a grails action, 'validateUsername' which determines whether the username is in use or not. The Server's response will be used to determine which of the messages contained within the hidden div's are displayed.

Step 4: Code up the grails action to validate the Text-field

In this step we implement the grails action which will receive the text-field content and validate it accordingly. For the purposes of this example I have used a simple list. You can easily replace this with code to inspect the database using GORM.


def validateUsername = {
       def message = "fail"

def inUse = ["homer", "marge", "bart", "maggie", "lisa"]

if (params.username)
{
if(inUse.contains(params.username))
{
message = "fail"
}
else
{
message = "ok"
}
}

render message

}





Quite simple really. The action will perform the uniqueness validation and return the result to the client.

The two possible outcomes are shown below,




and,



That's almost it. One problem remains and that is if the User decides to hit the submit button when the username field has an invalid entry. To solve this simply alter your 'save' action as follows,


def save = {
            def member = new Member(params)

def inUse = ["homer", "marge", "bart", "maggie", "lisa"]

//check that username is still available

if(inUse.contains(member.username))
{
member.errors.rejectValue('username', 'member.username.validator.invalid')
render(view:'create',model:[member:member])
}


if(!member.hasErrors() && member.save())
{
flash.message = "Member ${member.id} created"
redirect(action:show,id:member.id)
}
else
{
render(view:'create',model:[member:member])
}
}





where 'member.username.validator.invalid' is a custom error message defined in the message.properties file. The code above will perform another validity check and ensure that in the case of failure, the User is redirected to the form and our custom error is displayed.

Finally this code could be improved by providing suggestions of usernames to the User.

Friday, 5 December 2008

grails: Implementing Search

The ability for a User to perform searches for entries in the database is a critical requirement for most web apps. Implementing such a feature from scratch can be a rather daunting task. Thankfully there are open source solutions that alleviate the need to build your own search engine. Two of these, Lucene and Compass are bundled into a grails plug-in, enabling you to provide a powerful and flexible search capability for your Users.

Implementing search using this plugin is actually quite simple, as I will demonstrate in this post.

Step 1: Download & Install Searchable plugin

The first step is to download and install the Searchable plugin. Navigate to your project folder and issue the following command from a console window.

grails install-plugin searchable
 



Please note this assumes you are using JDK1.5+. If however, you're still using JDK1.4, then invoke the above command ensuring that the term 'searchable' is replaced with 'searchable14'.

Step 2: Modify Domain class

Open up your Domain class and add the statement 'static searchable = true '. In the example below, my domain class is called Issue and is a simplification of an actual class that I'm developing for a pet project. This flag enables the plugin to identify which records are available for search.

class Issue{

String title
String description
String status
String priority

static searchable = true

static constraints = {
title()
description()
status(inList : ["UNASSIGNED", "ASSIGNED", "CLOSED"])
priority(inList: ["TRIVIAL", "MINOR", "MAJOR", "CRITICAL", "BLOCKER"])
}

String toString(){
return title
}
}




Step 3: Create Search Textfield.

The next step is to provide a search box into which the User can enter search parameters. I do this by creating a search textfield like the one below,


<g:form url='[controller: "searchable", action: "index"]' id="searchableForm" name="searchableForm" method="get">
      <g:textField name="q" value="${params.q}" size="15"/> <input type="submit" value="Search" />

</g:form>




The textfield is embedded within a form that will pass its contents to an 'index' action on the plugins 'search' controller, either when the User clicks on the 'search' button or hits the 'enter' key.

To show what this would look like, I've knocked up a simple web app using the Issue class above. We now have something that looks like this

You can clearly see the search box at the top of the navigation bar. I've used the bootstrap class to create some test data which are shown in the table. This data will enable me to demonstrate that the search capability works and returns the expected results.

Entering a value of "CLOSED" into the search box returns the following response,

Although the plugin has successfully returned the expected results, the presentation of the data leaves a lot to be desired. Our application no longer looks consistent. Every time a User performs a search they'll end up with a page that clearly doesn't look right and they'll have to click on the browser back button to navigate somewhere else. The next step should fix this.

Step 4: Edit View for Search Results

Create a new folder 'searchable' under grails-app/views.

In this folder we want to place a copy of the view used by the plugin to display the results. The copy will subsequently be modified to generate a view that is consistent with our web application. So copy the file web-app/plugins/searchable-0.5.1/grails-app/views/searchable/index.gsp into the newly created folder. Here /web-app/ is the name of your project and searchable-0.5.1 refers to the version of the plugin that is in use. For my case, this happens to be 0.5.1. Check the version that you have downloaded and adjust accordingly.

Next we modify index.gsp in the following way,
  1. Delete all the css styling defined within the <head> tags
  2. Place the following meta-tag between the <head> tags
<meta name="layout" content="main"/>



Following these two steps should be sufficient to generate a results view that is consistent with your application. However for my application, I had to perform an extra step and rename the id's for the <header> and <main> divs. This was to prevent a conflict with css styling from my own style sheet.

The end result now looks like



This completes the tutorial, which I hope you will find useful. My intention was to enable you to get started quickly and in that respect the post has not and could not cover the full power of this fantastic plugin. That may be a task for another day.

The example code demonstrated here is available for download [compass.zip] from here. Please note that this is missing the plugin. I had to delete that in order to comply with the File Upload limit. However this shouldn't be a problem if you follow the installation instructions given above.

Tuesday, 2 December 2008

grails: Templates


Previously I've used Tiles to provide a common look and feel to web applications.

Template frameworks like Tiles achieve this effect by enabling developers to define page fragments which are then assembled into a complete page at run time. This approach is quite appealing since the fragments are by nature reusable view components, thereby enhancing maintainability and reducing development time.

Grails uses 'SiteMesh' to perform this function, and does so in a simple and flexible way. No XML configuration here !!!

A typical page layout is displayed in the figure on the left. This is made up from the following view components. The topbar will display time/date and a welcome message identifying the user, and potentially a 'logout' button. The header will showcase the name of the application, and the navbar will contain a menu for navigation. The central panel will contain the content to be displayed to the user. Finally the footer will hold information such as Terms & Conditions, a Copyright notice etc.

To implement the layout shown here execute the following steps,

Step 1: start
You need a project, ideally populated with at least a single domain class with it's associated controllers and views. The picture below shows the default layout generated by grails.



Step 2: create re-usable templates
With the exception of the header and content fragments, we start by creating the templates for the remaining view elements. Create a folder called 'common' under the views/ folder. In this folder create the following files
  • _topbar.gsp
  • _navbar.gsp
  • _footer.gsp
Note that these files should start with an underscore, '_' and should not contain any HTML tags such as <head>, <body>.

Step 3: populate _topbar.gsp

<div id="welcome">
12th June 2008
</div>

<div id="menu">
Welcome Ned Flanders | <a href="#">logout</a>
</div>




Step 4: populate _navbar.gsp

<div class='navbarBox'>

<div class="navcontainer1">
<h1 class="panelHeader">
Users
</h1>
<ul class="navlist">
<li>
<g:link controller="user" action="list">
List Users
</g:link>
</li>
<li>
<g:link controller="user" action="create">
Add User
</g:link>
</li>
<li>
<g:link controller="user" action="edit">
Edit User
</g:link>
</li>
<li style="color:grey"><a href="#">Remove User</a></li>
</ul>
</div>

</div>

<div class="navbarBox">

<div class="navcontainer1">
<h1 class="panelHeader">
Actions
</h1>
<ul class="navlist">
<li><a href="#">do something 1</a></li>
<li><a href="#">do something 2</a></li>
<li><a href="#">do something 3</a></li>
<li><a href="#">do something 4</a></li>
<li><a href="#">do something 5</a></li>
</ul>
</div>

</div>

<div class='navbarBox'>

<div class="navcontainer1">
<h1 class="panelHeader">
Leisure
</h1>
<ul class="navlist">
<li><a href="#">Activity 1</a></li>
<li><a href="#">Activity 2</a></li>
<li><a href="#">Activity 3</a></li>
<li><a href="#">Activity 4</a></li>
<li><a href="#">Activity 5</a></li>
</ul>
</div>

</div>




Step 5: populate _footer.gsp

<span class="copyright"> © 2008</span>
<span class="tandc"> <a href="#">Terms & Conditions </a></span>



Step 6: modify main.gsp

Once the reusable view components have been defined, we include them into the layout. Open the file /views/layout/main.gsp and replace all the code between the <body> tags with the following lines of code

<div id="page">

<div id="topbar">
<g:render template="/common/topbar" />
</div>

<div id='header'>
<h1 style="font-size:62px;text-align:center;"> Moongrails </h1>
</div>

<div id="content">
<g:layoutBody />
</div>

<div id='navbar'>
<g:render template="/common/navbar" />
</div>

<div id="footer">
<g:render template="/common/footer" />
</div>

</div>



The content in the central fragment will be populated by the gsp pages in the various view folders. When the user navigates to any particular page, e.g. /user/list.gsp, grails imports in the contents of that page and inserts it into the content div via the <g:layoutBody /> tag.

Step 7: modify main.css

The final step is to code up the styling for the various templates.

/* --------------------------------------*/
/* PAGE container */
/* --------------------------------------*/
/* Contains page contents e.g header,navbar, content, footer */
#page {
width: 90%;
margin: 0px auto;
padding: 4px 0;
text-align:left;
}


/* --------------------------------------*/
/* TOPBAR */
/* --------------------------------------*/
#topbar {
text-align:left;
padding:5px 0;
border-top: 1px solid #333;
background: #aaaaaa;
height: 15px;
}

#topbar #welcome{
float:left;
text-align:left;
font-size: 12px;
padding: 0px 0px 0px 10px;
color: #ffffff;
}

#topbar #menu{
float: right;
text-align: right;
font-size: 12px;
color: #ffffff;
}

#topbar #menu a{
color: #ffffff;
padding: 0px 10px 0px 0px;
}

/* --------------------------------------*/
/* HEADER */
/* --------------------------------------*/
#header {
background: #227ce8;
height: 150px;
margin: 0px auto;
border-top: solid 2px #000000;
}

#header h1 {
font-family:Arial,sans-serif;
color: white;
padding: 20px 0 0 6px;
font-size:1.6em;
}

/* --------------------------------------*/
/* CONTENT */
/* --------------------------------------*/
#content {
float: left;
width: 80%;
color: #000;
margin: 0 0.5em 0 0;
padding: 0px 10px 5px 0px;
}

/* --------------------------------------*/
/* NAVBAR */
/* --------------------------------------*/
#navbar {
float: right;
width: 210px;
color: #ff0000;
padding: 0px 5px 0px 5px;
margin: 0 0 0 0;
border-left: 1px solid #d3d3d3;
border-right: 1px solid #d3d3d3;
}


/*2.12.08 IE correction to drop sidbarBox*/
html>body #navbar .navbarBox {

width: 200px;
color: #0000ff;
background: #2175bc;
margin: 0px 5px 5px 5px ; /*ensure there's a gap between text in navbar and start of navbar*/
}

/*Header for boxes in navbar menu*/
#navbar .navbarBox h1{
background: #227ce8;
color: #ffffff;
font-weight: normal;
font-size: 16px;
}

/* --------------------------------------*/
/* FOOTER */
/* --------------------------------------*/
#footer {
border: solid 1px #000000;
height: 20px;
clear:both;
padding:5px;
margin: 5px 5px 5px 5px;
background: #ababab url(../images/footer.png) repeat;
}

#footer .tandc{
float: right;
color: #0000ff;
}

#footer .copyright{
float: left;
color: #0000ff;
}

/*----------------------------------------------------------*/
/* Improved vertical menu for navbar: see http://css.maxdesign.com.au/listamatic/vertical10.htm
/*----------------------------------------------------------*/

h1.panelHeader{
font-weight: bold;
text-align: center;
}

/*need html>body hack otw menu boxes, e.g. navbarbx all merge together*/
html>body .navcontainer1
{
width: 100%;
border-right: 1px solid #000;
font-family: Verdana, Lucida, Geneva, Helvetica, Arial, sans-serif;
background-color: #227ee8;
color: #333;
}

.navcontainer1 ul
{
list-style: none;
margin: 0;
padding: 0;
border-top: 2px solid #000000;
}

.navcontainer1 li
{
border-bottom: 1px solid #90bade;
margin: 0;
}

.navcontainer1 li a
{
display: block;
padding: 5px 5px 5px 0.5em;
border-left: 10px solid #1958b7;
border-right: 10px solid #508fc4;
background-color: #2175bc;
color: #ffffff;
text-decoration: none;
}

html>body .navcontainer1 li a { width: auto; }

.navcontainer1 li a:hover
{
border-left: 10px solid #1c64d1;
border-right: 10px solid #5ba3e0;
background-color: #2586d7;
color: #fff;
}





The menu in the navbar was styled using resources from Listomatic's Menu Tutorial. This is an excellent site which provides hints on how to create and style vertical/horizontal css menus.

The final result is displayed below.



The application suffers from at least a couple of problems when viewed using IE6. One of these shows the menu items in the navbar displayed in gray even though the css marks them to be white. To resolve this simply remove 'a:visited' from the line

a:link, a:visited, a:hover {



in the file main.css.

This example was developed using grails 1.03 and can be downloaded [templates.zip] from here.

Monday, 1 December 2008

grails: jQuery '$' conflicts

I'm a keen user of jQuery, which I've found to be a very robust, reliable and fairly intuitive javascript library. It offers tonnes of documentation in addition to a vast library of plugins to cater for most if not all your needs.

My experience with this library has been primarily problem-free except for one occasion when I attempted to use it in conjunction with another javascript library. Specifically, I discovered that previously working code implementing jQuery ceased to function when I imported in the scriptaculous library.

Generally jQuery has been well designed to circumvent potential collisions with other libraries through the use of a unique namespace. In spite of this, problems do occur, because of the role of the '$' function in jQuery and other competing libraries. In jQuery it is a shortcut reference to jQuery but means something different for scriptaculous. The solution to this problem is actually quite straightforward and is documented here.

Consider the following code [described in post: grails: toggling Form elements, step 3]



<g:javascript>
    $(document).ready(function() {

$("#status").change(function() {
$.ajax({
url: "/myform/issue/selectOutcome",
data: "status=" + this.value,
cache: false,
success: function(html) {$("#selectOutcome").html(html);}
});
}
);

});

</g:javascript>







This code allows us to use ajax to display/hide form elements based upon the selection made by a user from a drop down list. The code works fine, until I import in scriptaculous


<g:javascript library="scriptaculous"/>



Following this step, I discovered that the previous code stopped working. Implementing the suggestions provided by the jQuery website, I modified the above code as follows



<g:javascript>
    var $j = jQuery.noConflict();

$j(document).ready(function() {

$j("#status").change(function() {
$j.ajax({
url: "/myform/issue/selectOutcome",
data: "status=" + this.value,
cache: false,
success: function(html) {$j("#selectOutcome").html(html);}
});
}
);

});

</g:javascript>




Looking carefully at the before and after code snippets, you can see that the main difference has been to replace '$' with the variable '$j' where j is simply an alias for the function jQuery.noConflict(). This function tells jQuery to ignore the $ function so that scriptaculous or some other library can use it. Modifying the code in this way enables both the scriptaculous and jQuery code to function as expected. QED.

Friday, 28 November 2008

grails: toggling Form elements

Occasionally the need arises to have form elements that can be displayed/hidden depending upon a selection made from a drop down list. In this post I demonstrate how this can be achieved using grails + jQuery. The example shown below was developed using grails.1.03 and jQuery-1.2.6

The demonstration is based upon a simplified example of a bug tracker I have been developing. In this example, the domain class, Issue, has 4 fields,
  • name
  • description
  • status [e.g. UNASSIGNED, ASSIGNED, CLOSED]
  • outcome [e.g. FIXED, NOT FIXED, DUPLICATE]
When a user is editing an issue, only the first three fields should be displayed by default.


It makes sense to display the outcome field only if an issue has been marked "CLOSED" as below. Changing the status to any other value will reset the form and the outcome field will be hidden.














Now to move onto the implementation details.

Step 1: Download & Import jQuery library

In this step you need to download jQuery and place it in the web-app/js folder.
Next you need to import it into the gsp page by placing the following statement between the <head> tags, e.g.



<g:javascript library="jquery-1.2.6.min"/>



Step 2: Create Basic Form Elements

Staying with the gsp page, we create a form and embed within it 2 key elements. The first of these is a drop-down list for the status field. The second element is a stub represented here as an empty table row. Depending on selections to the status field, the stub will either remain empty or be replaced by an extra form element, e.g. a drop-down list for the outcome field.

<tr>
<td valign="top" class="name">
<label for="status">Status:</label>
</td>

<td valign="top" class="value ${hasErrors(bean:issue,field:'status','errors')}">
<g:select id="status" name="status" from="${issue.constraints.status.inList}"
value="${issue.status}" ></g:select>
</td>

</tr>

<tr class="prop" id="selectOutcome"></tr>




Step 3: Code up Ajax call

Next we need to bind the status drop-down list with javascript functions that will detect user selection and transmit its value to a grails controller via Ajax. The .change() and .ajax() functions provided by jQuery fit the bill. They will send the value selected from the status list to the controller and replace the empty stub with any html content sent back.


<g:javascript>
    $(document).ready(function() {

$("#status").change(function() {
$.ajax({
url: "/myform/issue/selectOutcome",
data: "status=" + this.value,
cache: false,
success: function(html) {$("#selectOutcome").html(html);}
});
}
);

});

</g:javascript>








The first argument to the ajax function is the url to the grails action. This is of the form /web context/controller/action. The 'data' parameter is the value of the selection made by the user, and the success parameter will replace the empty stub with the response generated by the grails controller.

Step 4: Implement grails action code

/**
* Enable user to select outcome when issue is closed
*/
    def selectOutcome = {

String status = params.status

if(status == "CLOSED")
{
render (template:"selectOutcome")
}

render ""

}




This action defined within an appropriate controller, simply checks to see if the selection made by the user for the status field is set to "CLOSED". If true, it will render the content placed within the template file defined below.

Step 5: create template

Create a template file which should contain the form element you want to display/hide in your target gsp page. Note that this file should be named with a leading underscore, e.g. _selectOutcome.gsp


<td valign="top" class="name">
<label for="outcome">Outcome:</label>
</td>

<td valign="top" class="value ${hasErrors(bean:issue,field:'outcome','errors')}">
<g:select id="selectOutcome" name="outcome"
from="${Issue.constraints.outcome.inList}" value=""></g:select>
</td>





This will render a label and a select element for the outcome field.

That's it !

You can download the code for this example [myform.zip] here.

Following the steps above should enable you to implement a similar form toggling feature for your application. Bear in mind though, that there is a potential problem if you will be using jQuery in conjunction with other javascript libraries. However this is a post for another day.

Thursday, 27 November 2008

grails: many-to-many Backref exception

I ran into a rather interesting problem recently when attempting to save a many-to-many association between 2 domain objects. I've managed to reproduce the problem in a sanitised test case which I'll present here. The app was developed using grails 1.03.

Consider the domain classes, Project and User defined as follows



and



Note that I've used a List to store the objects on the other side of the many-to-many relationship. Next I create test data in the BootStrap class as follows,




Upon deploying the application, I get the following exception

Caused by: org.springframework.dao.DataIntegrityViolationException: not-null property references a null or transient value: Project._User_projectsBackref; nested exception is org.hibernate.PropertyValueException: not-null property references a null or transient value: Project._User_projectsBackref

This is rather puzzling. The exception suggests an object referencing issue, but it's not clear what this is. Equally baffling is the solution to this problem. The domain classes above use a List to store their many-to-many collaborators. By simply reverting to the default collection type, i.e. a Set, the problem disappears. So for the code above remove line 7 in both classes and the app should deploy without any problems.

I recently came across this JIRA ticket which suggests this is a problem the grails team are aware of.

Thursday, 13 November 2008

grails + ajax: autocomplete

Having an autocomplete feature on a textfield is a good way of improving user experience. As the user types a string, the textfield tries to anticipate what the user is typing and offers possible matches. Clicking on a match results in autopopulation of the textfield thereby saving time for the user.

In this post I describe a way of implementing this feature using grails and scriptaculous. To help explain the method, I will develop a simple application where we have a form containing a text field for countries of the world. As a user begins to enter the name of the country, the textfield presents a list of possible matches. Finding the country he wants, the user clicks on the entry and the textfield is immediately populated with the selection [see picture below].




















Before ploughing into the specific details of how to implement this feature, it's useful to gain a high level view of what is going on "under the hood".


To begin with, the textfield needs to be registered with an ajax function [defined within scriptaculous]. This function will detect keystrokes and then call an appropriate action within a grails controller. The action in turn will employ GORM to perform a hibernate search for records that match the pattern of text the user has just entered. The results from this search will be returned to the view and rendered as a list just under the text box.

So to build your own autocomplete search text field, you need to do the following,

Step 1: Import in scriptaculous

Copy and paste the following into the header element of your gsp page


<g:javascript library='scriptaculous'/>



Step 2: create the form with the text field and the supporting div

Within the gsp page create a text field and a supporting div to display the results of the autocomplete feature.


<g:form name="find"..... >

..............
..............

<%-- Text field supporting autocomplete --%>
<input type="text" id="autocomplete" name="autocomplete_parameter"/>


..........
..........

</g:form>

<%-- supporting div to display potential matches.--%>

<div id="autocomplete_choices" class="autocomplete" ></div>




Step 3: Implement grails action to respond to ajax call

In this section we create the action in a grails controller that will respond to the ajax function.

def ajaxAutoComplete = {

if(params.autocomplete_parameter)
{
def input = params.autocomplete_parameter + '%'

def list = Country.findAll("from Country as country
where lower(country.name) like :name", [name:input])

StringBuffer idList = new StringBuffer()

idList.append("<ul>")

list?.each{c -> idList.append("<li>" + c.name+"</li>")}

idList.append("</ul>")

render idList.toString()
}
}



The action receives a variable called autocomplete_parameter containing the keystrokes entered by the user. This string is used in a hibernate query to retrieve the set of countries with matching names. Finally the search results are embedded within a html list that is subsequently rendered to view.

Step 4:
Code up the ajax call

In this case, we're simply setting up and calling an ajax function [Ajax.Autocompleter] from scriptaculous.


<html>
<head>
<meta equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="layout" content="main">

<g:javascript library="'scriptaculous'/">

<g:javascript>
window.onload = function()
{
new Ajax.Autocompleter("autocomplete",
"autocomplete_choices",
"/autocomplete/country/ajaxAutoComplete",
{}
);
}
</g:javascript>





The first argument to this function is the id of the UI element we're monitoring, i.e. the textfield. Next we pass in the name of the element that will be updated with the results of the ajax call. Thirdly we pass in the url to the grails code that will service the ajax function. This url is of the form /web context/controller/action.

Step 5: Add styling to the supporting div.

Place the following excerpt into /web-app/css/main.css


div.autocomplete {
position:absolute;
width:250px;
background-color:#8cafea;
margin:0px;
padding:0px;
overflow:hidden;
border: 1px solid;
}

div.autocomplete ul {
list-style-type:none;
margin:0px;
padding:0px;
overflow:auto;
}

div.autocomplete ul li.selected { background-color: #294597; color: #ffffff}

div.autocomplete ul li {
list-style-type:none;
display:block;
margin:0 0 0 5;
padding:2px;
height:12px;
cursor:pointer;
}


Presto !!! We now have an autocomplete solution using grails + scriptaculous. This implementation could be improved further by limiting the number of matches found by hibernate to some number say 8. This would prevent situations whereby the user is inundated with a long list of possible matches. There are alternative ways to implement this feature. These include using the RichUI or GrailsUI plugins.

You can download this example [autocomplete.zip] here. This example was built using grails 1.03

Wednesday, 12 November 2008

grails: Hello

Hi,

I'm currently in the process of learning grails by working on a pet project [an issue/bug tracker]. It's my intention to report some of what i've learnt on this blog not only for future recall but also hoping that others may find some of it useful.

I selected a bug/issue tracker since it would capture many of the features you would expect to find on a business reporting tool. Furthermore there seems to be a splurge of example applications based on blogging tools. I wanted to do something different.

I plan to document this exercise and release it together with the source code so that others may use it to learn grails. The application is called 'Gravitium' which is a combination of 'Grails' and 'Vitium' [latin for fault or defect].

Typical features for this application include,
  • basic CRUD [using GORM]
  • security [using acegi plugin]
  • search [using the compass plugin]
  • Charts [using google-chart plugin]
  • Reporting [using jasper plugin]
Additionally the application will use JQuery to provide enriched ui experience to supplement the functionality provided by the scriptaculous library which is included with grails.

In future posts, I'll present examples of how to implement some of these features.

Here's a snapshot of the app as it stands.