<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-3498211330006616408</id><updated>2012-02-02T22:42:19.028-06:00</updated><category term='jquery'/><category term='grails'/><category term='jqueryui'/><category term='subreports'/><category term='jasper'/><category term='jqgrid'/><category term='multiple datasources'/><title type='text'>Thoughts from a code junkie....</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://aoathout.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3498211330006616408/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://aoathout.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Aaron Oathout</name><uri>http://www.blogger.com/profile/17544558400157608670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>15</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-3498211330006616408.post-6369587701049305567</id><published>2011-04-23T17:23:00.003-05:00</published><updated>2011-04-23T17:26:09.894-05:00</updated><title type='text'>Long Delay....</title><content type='html'>I had almost totally forgot about my blog. It's been a long time since I've posted something and I will try to fix that shortly.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I've been working a lot on native mobile apps lately (iPhone and Android) with Grails as the backend web layer. That has been a very interesting (and fun) journey.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If there is anything specific people would like me to cover from a Grails, Andoir, iPhone/iPad perspective just let me know and I'll add it to my list.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3498211330006616408-6369587701049305567?l=aoathout.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aoathout.blogspot.com/feeds/6369587701049305567/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://aoathout.blogspot.com/2011/04/long-delay.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3498211330006616408/posts/default/6369587701049305567'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3498211330006616408/posts/default/6369587701049305567'/><link rel='alternate' type='text/html' href='http://aoathout.blogspot.com/2011/04/long-delay.html' title='Long Delay....'/><author><name>Aaron Oathout</name><uri>http://www.blogger.com/profile/17544558400157608670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3498211330006616408.post-316729015024847832</id><published>2010-09-25T17:51:00.007-05:00</published><updated>2010-09-25T19:44:34.514-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='grails'/><category scheme='http://www.blogger.com/atom/ns#' term='subreports'/><category scheme='http://www.blogger.com/atom/ns#' term='jasper'/><title type='text'>Grails Jasper Plugin with Sub Reports</title><content type='html'>Reporting is one thing that I never seem to escape. Grails apps are no different. In normal Java apps I've used Jasper/iReports to handle reporting so I wanted to see if the Grails Jasper plugin was up to the task. Man was I glad to find out it was.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The requirements are fairly simple.&lt;div&gt;&lt;ol&gt;&lt;li&gt;Data for the report comes from my domain model, not SQL queries&lt;/li&gt;&lt;li&gt;Sub Reports had to be supported&lt;/li&gt;&lt;/ol&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;&lt;div&gt;Domain Objects&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;For this example I'm only using two domain objects. I have an 'Artist' object that has a 'name' property and a 'hasMany' 'Album' definition. The 'Album' object has only a 'name' property, but 'belongsTo' 'Artist'. (Download the project to view the full source)&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;iReport&lt;/div&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;iReport lets you visually design your *.jrxml files. Plus you can precompile the jrxml files so you don't take the compilation hit when the reports are requested. I'm not going to go into a lot of detail on using iReport. There are plenty of resources on the net for that, plus the tool is pretty simple. I will point out some important settings that are needed so everything works.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;When you create the report file, don't specify a datasource. The Jasper plugin will use a '&lt;i&gt;JRBeanCollectionDataSource&lt;/i&gt;' for the information that is passed in. To access the fields in the datasource that is passed in you must create some fields in iReport. For this example we have two fields off the 'Artist' domain object we want to use in the report&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;name  (string )&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;albums (collection)&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;When you create these fields in iReport, make sure the 'Description' value on the field is the exact name of the field you want to show. It doesn't seem to be enough that the 'Name' field holds the path. The 'name' field will display in one band, while the 'albums' field will get passed to the sub-report so we can cycle over all the items.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;When you create the Sub Report element for the 'albums' field you need to have the following settings:&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;Connection Type: 'Use a datasource expression'&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;Data Source Expression: new net.sf.jasperreports.engine.data.JRBeanCollectionDataSource($F{albums})&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;This tells Jasper that when the report is populated and the sub report is called, use the 'albums' collection field off the 'Artist' object as the datasource for the sub report. &lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;Controller&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;The controller logic is pretty simple. We want to pull all 'Artists' from the database and pass that collection as the datasource for the report. The code is listed below&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;&lt;pre style="font-size: small;"&gt;&lt;br /&gt;def artistList = {&lt;br /&gt;&lt;br /&gt;    def reportDetails = Artist.listOrderByName([fetch:[albums: 'join']]);&lt;br /&gt;&lt;br /&gt;    // Set params that will be passed to Jasper&lt;br /&gt;    params.SUBREPORT_DIR = "${servletContext.getRealPath('/reports')}/"&lt;br /&gt;    params.IMAGE_DIR = "${servletContext.getRealPath('/images')}/"&lt;br /&gt;&lt;br /&gt;    chain(controller: 'report', action: 'generateReport', model: [data: reportDetails], params: params)&lt;br /&gt;  }&lt;/pre&gt;&lt;div&gt;Since we are using sub reports we need to pass in the location where the sub reports are located. Also, since we are using the grails-logo image in the header so we need to pass in the location where the image can be found. &lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;You will notice that the 'chain' call references the report.generateReport method. Normally you would send things to the 'jasper' controller, but I noticed an issue with using custom attachment filenames in the current JasperController code. I have created a Jira issue for the problem: &lt;a href="http://jira.codehaus.org/browse/GRAILSPLUGINS-2516"&gt;http://jira.codehaus.org/browse/GRAILSPLUGINS-2516&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;/div&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;View&lt;/span&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;The view changes are very simple. Run 'grails generate-views reporting.Artist' and edit the 'list.gsp' file. At the end of the file we add the following so the report can be downloaded:&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;pre style="font-size: small;"&gt;&amp;lt;g:jasperReport&lt;br /&gt;   jasper="artists.jasper"&lt;br /&gt;   name="artists-list-${new Date().format('MMddyy')}"&lt;br /&gt;   controller="report"&lt;br /&gt;   action="artistList"&lt;br /&gt;   format="pdf"&lt;br /&gt;   description="Download Artist List"&lt;br /&gt;   delimiter=" "/&amp;gt;&lt;br /&gt;&lt;/pre&gt;And that is it. We can now download a pdf report using our data from grails. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;Resources&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;Source: &lt;a href="http://sites.google.com/site/aoathout/reporting-post.tgz"&gt;http://sites.google.com/site/aoathout/reporting-post.tgz&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3498211330006616408-316729015024847832?l=aoathout.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aoathout.blogspot.com/feeds/316729015024847832/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://aoathout.blogspot.com/2010/09/grails-jasper-plugin-with-sub-reports.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3498211330006616408/posts/default/316729015024847832'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3498211330006616408/posts/default/316729015024847832'/><link rel='alternate' type='text/html' href='http://aoathout.blogspot.com/2010/09/grails-jasper-plugin-with-sub-reports.html' title='Grails Jasper Plugin with Sub Reports'/><author><name>Aaron Oathout</name><uri>http://www.blogger.com/profile/17544558400157608670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3498211330006616408.post-6030564262032972513</id><published>2010-09-20T20:07:00.002-05:00</published><updated>2010-09-20T20:14:39.239-05:00</updated><title type='text'>Grails JQGrid Plugin Released</title><content type='html'>The Grails JQGrid Plugin has been officially released. To make things easy the code for this plugin is no longer being maintained on github. It has now moved to the main Grails Plugin SVN repo (I don't really care for svn, but since I have 'git svn' I'm not gonna complain too loud ;) You can find the plugin information here: &lt;a href="http://grails.org/plugin/jqgrid"&gt;http://grails.org/plugin/jqgrid&lt;/a&gt; &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Since the plugin is done and released (for now), and I have finally started to settle into my new job, I should have some more time to put info up. The next two things I'll talk about are WireFrames (using the &lt;a href="http://wireframesketcher.com/"&gt;http://wireframesketcher.com/&lt;/a&gt; eclipse plugin) and Jasper reports (using from grails, including subreports. No SQL datasources, you can find plenty of info on that with a simple google search).&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3498211330006616408-6030564262032972513?l=aoathout.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aoathout.blogspot.com/feeds/6030564262032972513/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://aoathout.blogspot.com/2010/09/grails-jqgrid-plugin-released.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3498211330006616408/posts/default/6030564262032972513'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3498211330006616408/posts/default/6030564262032972513'/><link rel='alternate' type='text/html' href='http://aoathout.blogspot.com/2010/09/grails-jqgrid-plugin-released.html' title='Grails JQGrid Plugin Released'/><author><name>Aaron Oathout</name><uri>http://www.blogger.com/profile/17544558400157608670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3498211330006616408.post-603353599859314595</id><published>2010-09-06T12:34:00.003-05:00</published><updated>2010-09-06T14:16:50.149-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='multiple datasources'/><category scheme='http://www.blogger.com/atom/ns#' term='grails'/><title type='text'>Using Grails Datasources Plugin</title><content type='html'>If you're like me, then it is very rare that all of the information you need to access is in a single database. Things seem to be partitioned by department, etc. and the app you are working on needs to integrate all of this information. The standard Grails datasource doesn't support binding different domain classes to different databases, but fortunately, Burt Beckwith has created a plugin to solve that problem. &lt;a href="http://www.grails.org/plugin/datasources"&gt;http://www.grails.org/plugin/datasources&lt;/a&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;In this post I'll show you how simple it is utilize the plugin to handle those integration issues. We'll create a very simple Contacts application where the &lt;i&gt;State&lt;/i&gt; and &lt;i&gt;Country &lt;/i&gt;domain objects pull their info from one database, while our &lt;i&gt;Contact &lt;/i&gt;and &lt;i&gt;Address &lt;/i&gt;domain objects will store/retrieve things from another.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;First things we need todo is create the project, intall the datasources plugin and create some domain classes.&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;&lt;i&gt;grails create-app contacts&lt;/i&gt;&lt;/li&gt;&lt;li&gt;&lt;i&gt;grails install-plugin datasources&lt;/i&gt;&lt;/li&gt;&lt;li&gt;&lt;i&gt;grails create-domain-class contacts.app.Contact&lt;/i&gt;&lt;/li&gt;&lt;li&gt;&lt;i&gt;grails create-domain-class contacts.app.Address&lt;/i&gt;&lt;/li&gt;&lt;li&gt;&lt;i&gt;grails create-domain-class contacts.common.Country&lt;/i&gt;&lt;/li&gt;&lt;li&gt;&lt;i&gt;grails create-domain-class contacts.common.State&lt;/i&gt;&lt;/li&gt;&lt;/ul&gt;The domain classes are listed below:&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;class Country {&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;String name&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;String code&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;static constraints = {&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;name(blank: false, unique: true)&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;code(blank: false, unique: true)&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;String toString() {&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;name&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;}&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;class State {&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;String name&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;String code&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;Country country&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;static constraints = {&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;name(blank: false, unique: true)&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;code(blank: false, unique: true)&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;country(nullable: false)&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;String toString() {&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;name&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;}&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;class Address {&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;String line1&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;String line2&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;String city&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;Long stateId&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;String zip&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;static belongsTo = Contact&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;static constraints = {&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;line1(blank: false)&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;line2(nullable: true)&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;city(blank: false)&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;stateId(nullable: false)&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;zip(blank: false, matches: "^\\d{5}(-\\d{4})?")&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small; "&gt;}&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small; "&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small; "&gt;class Contact {&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small; "&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;String firstName&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small; "&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;String middleName&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small; "&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;String lastName&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small; "&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;String email&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small; "&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;String phone&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small; "&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;Address address&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small; "&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small; "&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;static constraints = {&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small; "&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;firstName(blank: false)&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small; "&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;middleName(nullable: true)&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small; "&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;lastName(blank: false)&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small; "&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;email(blank: false, email: true)&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small; "&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;phone(nullable: true, matches: "^\\(?(\\d{3})\\)?[- .]?(\\d{3})[- .]?(\\d{4})\$")&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;address(nullable: false)&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small; "&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-size: x-small; "&gt;}&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small; "&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small; "&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;String toString() {&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small; "&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;"${firstName} ${lastName}"&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small; "&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small; "&gt;}&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-small; "&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;One thing to note about the &lt;i&gt;Address&lt;/i&gt; class is it uses &lt;i&gt;Long stateId&lt;/i&gt; instead of binding to the &lt;i&gt;State&lt;/i&gt; object. Since &lt;i&gt;State&lt;/i&gt; is stored in a different database we only want to store the &lt;i&gt;id &lt;/i&gt;of the &lt;i&gt;State&lt;/i&gt; object. When we need to access the &lt;i&gt;State&lt;/i&gt; object we can simply look it up.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;Finally we need to add to configure the datasources we are going to use. Add a &lt;i&gt;Datasources.groovy &lt;/i&gt;file&lt;i&gt; &lt;/i&gt;to the &lt;i&gt;contacts/grails-app/conf &lt;/i&gt;folder. The contents of the file are listed below&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;  &lt;p class="p1"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;datasources = {&lt;/span&gt;&lt;/p&gt; &lt;p class="p1"&gt;&lt;span class="Apple-tab-span"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="s1"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;datasource&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;(name: &lt;/span&gt;&lt;span class="s2"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;'common'&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;) {&lt;/span&gt;&lt;/p&gt; &lt;p class="p1"&gt;&lt;span class="Apple-tab-span"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-tab-span"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="s1"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;pooled&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;(&lt;/span&gt;&lt;span class="s3"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;true&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;)&lt;/span&gt;&lt;/p&gt; &lt;p class="p1"&gt;&lt;span class="Apple-tab-span"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-tab-span"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="s1"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;domainClasses&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;([contacts.common.Country,&lt;/span&gt;&lt;/p&gt; &lt;p class="p1"&gt;&lt;span class="Apple-tab-span"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-tab-span"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;         &lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;      &lt;span class="Apple-tab-span" style="white-space:pre"&gt;    &lt;/span&gt;    contacts.common.State])&lt;/span&gt;&lt;/p&gt; &lt;p class="p1"&gt;&lt;span class="Apple-tab-span"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-tab-span"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="s1"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;readOnly&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;(&lt;/span&gt;&lt;span class="s3"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;false&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;)&lt;/span&gt;&lt;/p&gt; &lt;p class="p2"&gt;&lt;span class="s4"&gt;&lt;span class="Apple-tab-span"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-tab-span"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="s5"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;driverClassName&lt;/span&gt;&lt;/span&gt;&lt;span class="s4"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;'org.hsqldb.jdbcDriver'&lt;/span&gt;&lt;span class="s4"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/p&gt; &lt;p class="p2"&gt;&lt;span class="s4"&gt;&lt;span class="Apple-tab-span"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-tab-span"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="s5"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;url&lt;/span&gt;&lt;/span&gt;&lt;span class="s4"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;'jdbc:hsqldb:mem:commonDB'&lt;/span&gt;&lt;span class="s4"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/p&gt; &lt;p class="p1"&gt;&lt;span class="Apple-tab-span"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-tab-span"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="s1"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;username&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;'sa'&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;)&lt;/span&gt;&lt;/p&gt; &lt;p class="p1"&gt;&lt;span class="Apple-tab-span"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-tab-span"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="s1"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;password&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;''&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;)&lt;/span&gt;&lt;/p&gt; &lt;p class="p2"&gt;&lt;span class="s4"&gt;&lt;span class="Apple-tab-span"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-tab-span"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="s5"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;dbCreate&lt;/span&gt;&lt;/span&gt;&lt;span class="s4"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;'create-drop'&lt;/span&gt;&lt;span class="s4"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/p&gt; &lt;p class="p1"&gt;&lt;span class="Apple-tab-span"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-tab-span"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="s1"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;logSql&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;(&lt;/span&gt;&lt;span class="s3"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;false&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;)&lt;/span&gt;&lt;/p&gt; &lt;p class="p1"&gt;&lt;span class="Apple-tab-span"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;}&lt;/span&gt;&lt;/p&gt; &lt;p class="p1"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;}&lt;/span&gt;&lt;/p&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;And that is it. Our &lt;i&gt;Country &lt;/i&gt;and &lt;i&gt;State&lt;/i&gt; objects will use the &lt;i&gt;common&lt;/i&gt; datasource while all other objects use the default datasource. The source for this post has a few modifications to the view files for &lt;i&gt;Contact&lt;/i&gt; along with some default data in &lt;i&gt;BootStrap.groovy&lt;/i&gt;. One thing I should point out is the default database will have tables defined for both &lt;i&gt;Country &lt;/i&gt;and &lt;i&gt;State&lt;/i&gt;. This is noted on the &lt;i&gt;datasources&lt;/i&gt; plugin page.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Source: &lt;a href="https://sites.google.com/site/aoathout/contacts.tgz"&gt;https://sites.google.com/site/aoathout/contacts.tgz&lt;/a&gt;&lt;/div&gt;&lt;div&gt;Datasources Plugin: &lt;a href="http://www.grails.org/plugin/datasources"&gt;http://www.grails.org/plugin/datasources&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;&lt;br /&gt;&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;&lt;br /&gt;&lt;/i&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3498211330006616408-603353599859314595?l=aoathout.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aoathout.blogspot.com/feeds/603353599859314595/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://aoathout.blogspot.com/2010/09/using-grails-datasources-plugin.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3498211330006616408/posts/default/603353599859314595'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3498211330006616408/posts/default/603353599859314595'/><link rel='alternate' type='text/html' href='http://aoathout.blogspot.com/2010/09/using-grails-datasources-plugin.html' title='Using Grails Datasources Plugin'/><author><name>Aaron Oathout</name><uri>http://www.blogger.com/profile/17544558400157608670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3498211330006616408.post-3830939313006557820</id><published>2010-08-26T21:46:00.002-05:00</published><updated>2010-08-26T22:18:20.497-05:00</updated><title type='text'>Grails Tutorial - Part 4</title><content type='html'>&lt;p&gt;This post is gonna be fairly brief. I'm gonna introduce the Grails jqgrid&lt;br /&gt;       plugin and replace the current Instrument, Member and Band list page with the jqgrid plugin&lt;br /&gt;       taglib. This will reduce the amount of code we have to write from well over 100 lines&lt;br /&gt;       to about 50 lines (with formatting/spacing ;)&lt;/p&gt;      &lt;b&gt;Why use the jqGrid plugin?&lt;/b&gt;&lt;p&gt;          Well, frankly I hate to repeat myself. While jquery/jquery-ui/jqgrid&lt;br /&gt;         are easy enough to use on their own, I don't like to type/copy-paste&lt;br /&gt;         a bunch of code when there are easier ways todo things. That is why&lt;br /&gt;         I created the jqgrid plugin and why I am going to introduce it here.&lt;br /&gt;     &lt;/p&gt;      &lt;b&gt;Where can I find the plugin?&lt;/b&gt;&lt;p&gt;        The plugin work has just started but so far it handles 90% of everything&lt;br /&gt;       I need todo for a grid. I plan on implementing every feature of jqgrid&lt;br /&gt;       but for now it is a good start.&lt;br /&gt;&lt;br /&gt;       You can find the code here: &lt;a href="http://www.blogger.com/post-edit.g?blogID=3498211330006616408&amp;amp;postID=3830939313006557820" com="" jqgrid=""&gt;&lt;br /&gt;       Grails JQGrid Plugin&lt;/a&gt;. It should handle most things you need todo, but&lt;br /&gt;       in the case where it doesn't, feel free to email me, or better yet, fork&lt;br /&gt;       the project off github! (It is good to be a social programmer!)&lt;br /&gt;     &lt;/p&gt;      &lt;b&gt;Installing the plugin&lt;/b&gt;&lt;p&gt;        Installation is fairly simple. Download the grails jqgrid plugin, run&lt;br /&gt;       "grails package-plugin" inside the grails-jqgrid/jqgrid project. Then&lt;br /&gt;       inside the myband app run "grails install-plugin "&amp;lt;path-to-grails-jqgrid-plugin-zip&gt;"&lt;br /&gt;       ** Once the plugin is officially released you will be able to download&lt;br /&gt;       from the main grails plugin site&lt;br /&gt;     &lt;/p&gt;      &lt;b&gt;Project Modifications&lt;/b&gt;&lt;br /&gt;     &lt;p&gt;The first we do is remove alot of &lt;code&gt;&amp;lt;g:javascript/&amp;gt;&lt;/code&gt;&lt;br /&gt;         from our main.gsp file. The following is what our final main.gsp page.&lt;br /&gt;     &lt;/p&gt;&lt;pre style="font-size: small;"&gt;&lt;br /&gt;&amp;lt;!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"&lt;br /&gt; "http://www.w3.org/TR/html4/strict.dtd"&amp;gt;&lt;br /&gt;&amp;lt;html&amp;gt;&lt;br /&gt; &amp;lt;head&amp;gt;&lt;br /&gt;   &amp;lt;meta http-equiv="PRAGMA" content="NO-CACHE"&amp;gt;&lt;br /&gt;   &amp;lt;meta http-equiv="CACHE-CONTROL" content="NO-CACHE"&amp;gt;&lt;br /&gt;   &amp;lt;meta http-equiv="EXPIRES" content="Mon, 22 Jul 2002 11:12:01 GMT"&amp;gt;&lt;br /&gt;   &amp;lt;meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /&amp;gt;&lt;br /&gt;&lt;br /&gt;   &amp;lt;title&amp;gt;&amp;lt;g:layoutTitle default="MyBand" /&amp;gt;&amp;lt;/title&amp;gt;&lt;br /&gt;&lt;br /&gt;   &amp;lt;link rel="stylesheet" href="${resource(dir:'css/menu', file:'fg.menu.css')}" /&amp;gt;&lt;br /&gt;   &amp;lt;link rel="stylesheet" href="${resource(dir:'css', file:'main.css')}" /&amp;gt;&lt;br /&gt;   &amp;lt;link rel="stylesheet" href="${resource(dir:'css', file:'site.css')}" /&amp;gt;&lt;br /&gt;   &amp;lt;link rel="stylesheet" href="${resource(dir:'css', file:'messages.css')}" /&amp;gt;&lt;br /&gt;&lt;br /&gt;   &amp;lt;jq:resources /&amp;gt;&lt;br /&gt;   &amp;lt;jqui:resources /&amp;gt;&lt;br /&gt;   &amp;lt;!-- tooltip is still alpha/beta so not included in jquery-ui grails plugin&lt;br /&gt;        Tooltip is needed for live validation --&amp;gt;&lt;br /&gt;   &amp;lt;g:javascript library="jquery-ui/jquery.ui.tooltip"/&amp;gt;&lt;br /&gt;   &amp;lt;g:javascript library="menu/fg.menu" /&amp;gt;&lt;br /&gt;&lt;br /&gt;   &amp;lt;g:javascript library="app/application" /&amp;gt;&lt;br /&gt;   &amp;lt;g:javascript library="app/menu" /&amp;gt;&lt;br /&gt;&lt;br /&gt;   &amp;lt;script type="text/javascript" src="http://jqueryui.com/themeroller/themeswitchertool/"&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&lt;br /&gt;   &amp;lt;g:layoutHead /&amp;gt;&lt;br /&gt; &amp;lt;/head&amp;gt;&lt;br /&gt; &amp;lt;body class="ui-widget-content"&amp;gt;&lt;br /&gt;     &amp;lt;div id="header" class="ui-widget-header"&amp;gt;&lt;br /&gt;        &amp;lt;!-- Site banner / include should go here --&amp;gt;&lt;br /&gt;     &amp;lt;/div&amp;gt;&lt;br /&gt;&lt;br /&gt;     &amp;lt;g:render template="/layouts/includes/menu" /&amp;gt;&lt;br /&gt;&lt;br /&gt;     &amp;lt;!-- We need some type of top level menu (fgMenu) --&amp;gt;&lt;br /&gt;     &amp;lt;div id="bodyContent"&amp;gt;&lt;br /&gt;       &amp;lt;div id="switcher" style="margin-top: 5px;"&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;       &amp;lt;div id="sidebar"&amp;gt;&lt;br /&gt;         &amp;lt;!-- Provide some sidebar navigator (accordian) here --&amp;gt;&lt;br /&gt;         &amp;lt;g:render template="/layouts/includes/leftnav" /&amp;gt;&lt;br /&gt;       &amp;lt;/div&amp;gt;&lt;br /&gt;&lt;br /&gt;       &amp;lt;div id="main"&amp;gt;&lt;br /&gt;         &amp;lt;!-- Main Body section. Other views will define the content --&amp;gt;&lt;br /&gt;         &amp;lt;g:layoutBody/&amp;gt;&lt;br /&gt;       &amp;lt;/div&amp;gt;&lt;br /&gt;     &amp;lt;/div&amp;gt;&lt;br /&gt;&lt;br /&gt;     &amp;lt;div id="footer" class="ui-widget ui-widget-header"&amp;gt;&lt;br /&gt;       &amp;lt;!-- Put some footer / copyright info here --&amp;gt;&lt;br /&gt;       &amp;lt;div id="footerContent"&amp;gt;&lt;br /&gt;         MyBand &amp;lt;g:meta name="app.version"/&amp;gt; on Grails &amp;lt;g:meta name="app.grails.version"/&amp;gt;.&lt;br /&gt;       &amp;lt;/div&amp;gt;&lt;br /&gt;     &amp;lt;/div&amp;gt;&lt;br /&gt;&lt;br /&gt; &amp;lt;/body&amp;gt;&lt;br /&gt;&amp;lt;/html&amp;gt;&lt;br /&gt;   &lt;/pre&gt;Next lets look at the tag contents for the band page.&lt;pre style="font-size: small;"&gt; &amp;lt;jqgrid:grid&lt;br /&gt;         id="band"&lt;br /&gt;         listUrl="${createLink(action: 'listJSON')}"&lt;br /&gt;         editUrl="${createLink(action: 'editJSON')}"&lt;br /&gt;         colNames="'Name', 'Members', 'id'"&lt;br /&gt;         colModel="{name:'name', editable: true},&lt;br /&gt;                   {name:'members', editable: false, sortable: false},&lt;br /&gt;                   {name:'id', hidden: true}"&lt;br /&gt;         sortName="name"&lt;br /&gt;         caption="Band List"&lt;br /&gt;         height="300"&lt;br /&gt;         filterToolBar="true"&lt;br /&gt;         onDblClickRow="onDblClickRow"&lt;br /&gt;         searchOnEnter="false"&lt;br /&gt;         viewRecords="true"&amp;gt;&lt;br /&gt;&lt;br /&gt;         &amp;lt;jqgrid:deleteButton&lt;br /&gt;             id="band"&lt;br /&gt;             url="${createLink(action: 'editJSON')}"&lt;br /&gt;             messageId="message"/&amp;gt;&lt;br /&gt;&lt;br /&gt;         &amp;lt;jqgrid:editButton&lt;br /&gt;             id="band"&lt;br /&gt;             url="${createLink(action: 'edit')}"&lt;br /&gt;             messageId="message"/&amp;gt;&lt;br /&gt;&lt;br /&gt;         &amp;lt;jqgrid:addButton&lt;br /&gt;             id="band"&lt;br /&gt;             url="${createLink(action: 'create')}"&lt;br /&gt;             messageId="message"/&amp;gt;&lt;br /&gt;&lt;br /&gt;         &amp;lt;jqgrid:searchButton id="band" /&amp;gt;&lt;br /&gt;&lt;br /&gt;     &amp;lt;/jqgrid:grid&amp;gt;&lt;br /&gt;       &lt;/pre&gt;        Pretty simple. If you want more info on jqGrid or the jqGrid tag-lib&lt;br /&gt;       you can find links in the resource section.&lt;br /&gt;      &lt;br /&gt;The last point I should mention is the Grid service for the Band list page.&lt;pre style="font-size: small;"&gt;    class BandGridService extends GridService {&lt;br /&gt;&lt;br /&gt;       boolean transactional = true&lt;br /&gt;&lt;br /&gt;       def processor = { results -&gt;&lt;br /&gt;           def cells = results.collect {&lt;br /&gt;               [&lt;br /&gt;                   cell: [&lt;br /&gt;                       it.name,&lt;br /&gt;                       it.members*.toString()&lt;br /&gt;                   ],&lt;br /&gt;                   id: it.id&lt;br /&gt;               ]&lt;br /&gt;           }&lt;br /&gt;           return cells&lt;br /&gt;       }&lt;br /&gt;&lt;br /&gt;       @Override&lt;br /&gt;       Map generate(Map params, String entity) {&lt;br /&gt;           generate(params, entity, processor)&lt;br /&gt;       }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;       @Override&lt;br /&gt;       List query(Map params, Integer maxRows, Integer rowOffset,&lt;br /&gt;                  String sortIndex, String sortOrder, String domain) {&lt;br /&gt;           def instance = grailsUtilService.createDomainInstance(domain)&lt;br /&gt;           def results = instance.createCriteria().list(max: maxRows, offset: rowOffset) {&lt;br /&gt;               and {&lt;br /&gt;                   // case insensitive, term can be anywhere&lt;br /&gt;                   if (params.name)&lt;br /&gt;                       ilike('name', '%' + params.name + '%')&lt;br /&gt;&lt;br /&gt;                   if (params.members) {&lt;br /&gt;                       members {&lt;br /&gt;                           or {&lt;br /&gt;                               ilike('firstName', '%' + params.members + '%')&lt;br /&gt;                               ilike('lastName', '%' + params.members + '%')&lt;br /&gt;                           }&lt;br /&gt;                       }&lt;br /&gt;                   }&lt;br /&gt;               }&lt;br /&gt;               order(sortIndex, sortOrder).ignoreCase()&lt;br /&gt;               resultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY)&lt;br /&gt;           }&lt;br /&gt;           results&lt;br /&gt;       }&lt;br /&gt;   }&lt;br /&gt;       &lt;/pre&gt;&lt;b&gt;Other Stuff&lt;/b&gt;&lt;p&gt;          If you run the application you will see that the Member edit/create page&lt;br /&gt;         uses the multi-select list jquery plugin. It is pretty simple to use&lt;br /&gt;         (One line of jquery code) so I figure there is no point getting deep into&lt;br /&gt;         it. One thing though, I did modify the ui.multiselect.js file so the&lt;br /&gt;         available list shows on the left instead of the right. (It would be nice to&lt;br /&gt;         see a this become an option instead of changing code)&lt;br /&gt;     &lt;/p&gt;Alright, short post, but you should download the source and checkout the details.&lt;br /&gt;     I probably won't add much more for jqGrid and formular. The next post will&lt;br /&gt;     probably cover adding spring-security-core so we can authenticate users&lt;br /&gt;    &lt;br /&gt;&lt;b&gt;Resources&lt;/b&gt;&lt;br /&gt;     &lt;div&gt;Source: &lt;a href="https://sites.google.com/site/aoathout/myband-part4.zip"&gt;https://sites.google.com/site/aoathout/myband-part4.zip&lt;/a&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: rgb(255, 0, 0); "&gt;** After downloading, rename the folder to "myband".&lt;/span&gt;&lt;br /&gt;Grails: &lt;a href="http://www.grails.org/"&gt;http://www.grails.org&lt;/a&gt;&lt;br /&gt;jQuery: &lt;a href="http://jquery.com/"&gt;http://jquery.com&lt;/a&gt;&lt;br /&gt;jQuery UI: &lt;a href="http://jqueryui.com/"&gt;http://jqueryui.com&lt;/a&gt;&lt;br /&gt;jqGrid: &lt;a href="http://www.trirand.com/blog"&gt;http://www.trirand.com/blog&lt;/a&gt;&lt;br /&gt;JqGrid Grails Plugin: &lt;a href="http://aoathout.github.com/grails-jqgrid/"&gt;http://aoathout.github.com/grails-jqgrid&lt;/a&gt;&lt;br /&gt;fgMenu: &lt;a href="http://www.filamentgroup.com/lab/jquery_ipod_style_and_flyout_menus/"&gt;http://www.filamentgroup.com/lab/jquery_ipod_style_and_flyout_menus/&lt;/a&gt;&lt;br /&gt;Multi-Select List: &lt;a href="http://quasipartikel.at/multiselect/"&gt;http://quasipartikel.at/multiselect/&lt;/a&gt;&lt;br /&gt;Formular: &lt;a href="http://wiki.github.com/fnagel/jQuery-Accessible-RIA/formular"&gt;http://wiki.github.com/fnagel/jQuery-Accessible-RIA/formular&lt;/a&gt;&lt;br /&gt;Git: &lt;a href="http://git-scm.com/"&gt;http://git-scm.com&lt;/a&gt;&lt;br /&gt;     &lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3498211330006616408-3830939313006557820?l=aoathout.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aoathout.blogspot.com/feeds/3830939313006557820/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://aoathout.blogspot.com/2010/08/grails-tutorial-part-4.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3498211330006616408/posts/default/3830939313006557820'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3498211330006616408/posts/default/3830939313006557820'/><link rel='alternate' type='text/html' href='http://aoathout.blogspot.com/2010/08/grails-tutorial-part-4.html' title='Grails Tutorial - Part 4'/><author><name>Aaron Oathout</name><uri>http://www.blogger.com/profile/17544558400157608670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3498211330006616408.post-8384714207222011603</id><published>2010-08-04T19:13:00.004-05:00</published><updated>2010-08-04T19:24:45.036-05:00</updated><title type='text'>Gotta love changes</title><content type='html'>Just like everything in life, code changes all the time. JQGrid has released 3.8 which has some pretty cool features. Grails is set to release 1.3.4 early next week (Man, how can we keep up?). MyBand post is sidelined for the moment while I upgrade the grails jqgrid plugin to 3.8 (and because I'm doing some cool iphone development). I'll get things up as soon as I can. Sorry for the delay.&lt;br /&gt;&lt;br /&gt;While you wait you should check out the following grails plugins:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.grails.org/iwebkit+Plugin"&gt;iWebKit&lt;/a&gt; Plugin - Great plugin for mobile website development (Yeah, iPhone haters can say what they want, but face it, great phone/ui/platform)&lt;br /&gt;&lt;br /&gt;&lt;a href="http://grails.org/plugin/gsp-arse"&gt;GSParse&lt;/a&gt; Plugin - No more inline javascript! Plus you can use server-side script in  your CSS!! (About time somebody provided this. Thank you!!!!)&lt;br /&gt;&lt;br /&gt;&lt;a href="http://jqtouch.com/"&gt;JQTouch&lt;/a&gt; JQuery Plugin - Wish I would have seen this a long time ago.&lt;br /&gt;&lt;br /&gt;Always good plugins by Burt Beckwith (Thanks man. You really help keep this stuff going!!)&lt;br /&gt;&lt;a href="http://www.grails.org/plugin/spring-security-core"&gt;Spring Security&lt;/a&gt; (Check out the UI/ACL/CAS plugins as well)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3498211330006616408-8384714207222011603?l=aoathout.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aoathout.blogspot.com/feeds/8384714207222011603/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://aoathout.blogspot.com/2010/08/gotta-love-changes.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3498211330006616408/posts/default/8384714207222011603'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3498211330006616408/posts/default/8384714207222011603'/><link rel='alternate' type='text/html' href='http://aoathout.blogspot.com/2010/08/gotta-love-changes.html' title='Gotta love changes'/><author><name>Aaron Oathout</name><uri>http://www.blogger.com/profile/17544558400157608670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3498211330006616408.post-4743784568801227739</id><published>2010-07-29T00:00:00.003-05:00</published><updated>2010-07-29T00:04:04.415-05:00</updated><title type='text'>Grails JQGrid Plugin Update</title><content type='html'>I've added code to enable the default navigation bar and the ondblClickRow event listener. There is a lot more todo. Hopefully I will get time to add more features in the next day or so.&lt;br /&gt;&lt;br /&gt;Follow the instructions here: &lt;a href="http://aoathout.blogspot.com/2010/07/jqgrid-grails-plugin.html"&gt;http://aoathout.blogspot.com/2010/07/jqgrid-grails-plugin.html&lt;/a&gt; to build and install things.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3498211330006616408-4743784568801227739?l=aoathout.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aoathout.blogspot.com/feeds/4743784568801227739/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://aoathout.blogspot.com/2010/07/grails-jqgrid-plugin-update.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3498211330006616408/posts/default/4743784568801227739'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3498211330006616408/posts/default/4743784568801227739'/><link rel='alternate' type='text/html' href='http://aoathout.blogspot.com/2010/07/grails-jqgrid-plugin-update.html' title='Grails JQGrid Plugin Update'/><author><name>Aaron Oathout</name><uri>http://www.blogger.com/profile/17544558400157608670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3498211330006616408.post-8217871866309098078</id><published>2010-07-25T14:53:00.002-05:00</published><updated>2010-07-25T14:59:23.644-05:00</updated><title type='text'>JQGrid Grails Plugin</title><content type='html'>I have posted the initial code for the Grails JQGrid plugin. Currently it only supports JSON data and doesn't include things like inline editing or navigation bar controls. I hope to add those features this week.&lt;br /&gt;&lt;br /&gt;There are two projects for this plugin. One is the plugin code itself, the other is a demo app that shows how to use the taglib. To run the demo app you must first package the plugin.&lt;br /&gt;&lt;br /&gt;cd grails-jqgrid/jqgrid&lt;br /&gt;grails package-plugin&lt;br /&gt;&lt;br /&gt;Then in the demo application you must install the plugin (uninstalling any previous versions)&lt;br /&gt;cd grails-jqgrid/jqgrid-demo&lt;br /&gt;grails uninstall-plugin jqgrid&lt;br /&gt;grails install-plugin ../jqgrid/grails-jqgrid*.zip&lt;br /&gt;&lt;br /&gt;At this point you should be able to launch the application. If you navigate to the AuthorController you can view the list page as a jqgrid.&lt;br /&gt;&lt;br /&gt;You can find the code here:  &lt;a href="http://aoathout.github.com/grails-jqgrid/"&gt;http://aoathout.github.com/grails-jqgrid&lt;/a&gt;. I'm always open to suggestions and if you feel like helping with the project be my guest.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3498211330006616408-8217871866309098078?l=aoathout.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aoathout.blogspot.com/feeds/8217871866309098078/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://aoathout.blogspot.com/2010/07/jqgrid-grails-plugin.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3498211330006616408/posts/default/8217871866309098078'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3498211330006616408/posts/default/8217871866309098078'/><link rel='alternate' type='text/html' href='http://aoathout.blogspot.com/2010/07/jqgrid-grails-plugin.html' title='JQGrid Grails Plugin'/><author><name>Aaron Oathout</name><uri>http://www.blogger.com/profile/17544558400157608670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3498211330006616408.post-1589472160833241677</id><published>2010-07-20T14:51:00.002-05:00</published><updated>2010-07-20T14:53:42.433-05:00</updated><title type='text'>Missing Dependency in MyBand Application</title><content type='html'>It has been brought up that there is a missing dependency in the MyBand application (oracle jdbc driver). To fix this issue, simply edit the BuildConfig.groovy file and comment out the following line: "compile 'com.oracle:ojdbc6:11.2.0.1.0'". I will make sure the next post doesn't have this issue.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3498211330006616408-1589472160833241677?l=aoathout.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aoathout.blogspot.com/feeds/1589472160833241677/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://aoathout.blogspot.com/2010/07/missing-dependency-in-myband.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3498211330006616408/posts/default/1589472160833241677'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3498211330006616408/posts/default/1589472160833241677'/><link rel='alternate' type='text/html' href='http://aoathout.blogspot.com/2010/07/missing-dependency-in-myband.html' title='Missing Dependency in MyBand Application'/><author><name>Aaron Oathout</name><uri>http://www.blogger.com/profile/17544558400157608670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3498211330006616408.post-6778699305765881610</id><published>2010-07-13T20:15:00.000-05:00</published><updated>2010-07-13T20:16:02.595-05:00</updated><title type='text'>Grails Tutorial - Part 3</title><content type='html'>In part one we created the domain layer and generated the controllers.&lt;br /&gt;        In part two we changed our layout, css, added jquery and jquery-ui, theme&lt;br /&gt;        switcher and changed the homepage. In this post I'll cover changing the&lt;br /&gt;        generated list page. We will add the jqgrid component and modify the&lt;br /&gt;        Controllers to return json for our ajax requests.&lt;br /&gt;&lt;br /&gt;      &lt;b&gt;Why the jqGrid component?&lt;/b&gt;&lt;br /&gt;          I've chosen the jqGrid component because of the features. We'll start &lt;br /&gt;          with the basic jqGrid. (The band view will include some other options for the grid).&lt;br /&gt;&lt;br /&gt;      &lt;b&gt;Changing the list.gsp page&lt;/b&gt;&lt;br /&gt;        We'll start with something that has no relationships.&lt;br /&gt;        Open the "myband/grails-app/views/instrument/list.gsp" file and replace&lt;br /&gt;        all of the content with the following.&lt;br /&gt;        &lt;pre style="font-size: small;"&gt;&lt;br /&gt;            &amp;lt;html&amp;gt;&lt;br /&gt;              &amp;lt;head&amp;gt;&lt;br /&gt;                &amp;lt;meta name="layout" content="main" /&amp;gt;&lt;br /&gt;&lt;br /&gt;                &amp;lt;g:set var="entityName" value="${message(code: 'instrument.label', default: 'Instrument')}" /&amp;gt;&lt;br /&gt;&lt;br /&gt;                &amp;lt;script type="text/javascript"&amp;gt;&lt;br /&gt;                    // URL values used for list interaction&lt;br /&gt;                    // Defined here so we don't inline all of the javascript&lt;br /&gt;                    var listSourceUrl = "${createLink(action: 'listJSON')}";&lt;br /&gt;                    var listEditUrl = "${createLink(action: 'editJSON')}";&lt;br /&gt;                    var showUrl = "${createLink(action: 'show')}";&lt;br /&gt;                    var editUrl = "${createLink(action: 'edit')}";&lt;br /&gt;                    var createUrl = "${createLink(action: 'create')}";&lt;br /&gt;                &amp;lt;/script&amp;gt;&lt;br /&gt;&lt;br /&gt;                &amp;lt;g:javascript library="app/instrument/list" /&amp;gt;&lt;br /&gt;&lt;br /&gt;              &amp;lt;/head&amp;gt;&lt;br /&gt;              &amp;lt;body&amp;gt;&lt;br /&gt;                &amp;lt;div class="body"&amp;gt;&lt;br /&gt;                  &amp;lt;g:if test="${flash.message}"&amp;gt;&lt;br /&gt;                    &amp;lt;div id="message" class="message ui-widget-header ui-corner-all"&amp;gt;${flash.message}&amp;lt;/div&amp;gt;&lt;br /&gt;                  &amp;lt;/g:if&amp;gt;&lt;br /&gt;&lt;br /&gt;                  &amp;lt;div id="gridWrapper" class="ui-widget-header ui-corner-all" style="overflow: auto;"&amp;gt;&lt;br /&gt;                    &amp;lt;h3 class="ui-widget-header ui-corner-all" style="text-align: center;"&amp;gt;${entityName}s&amp;lt;/h3&amp;gt;&lt;br /&gt;                    &amp;lt;!-- table tag will hold our grid --&amp;gt;&lt;br /&gt;                    &amp;lt;table id="instrumentGrid" class="scroll jqTable" style="width: 100%;" cellpadding="0" cellspacing="0"&amp;gt;&amp;lt;/table&amp;gt;&lt;br /&gt;                    &amp;lt;!-- pager will hold our paginator --&amp;gt;&lt;br /&gt;                    &amp;lt;div id="instrumentGridPager" class="scroll" style="text-align:center;"&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;                  &amp;lt;/div&amp;gt;&lt;br /&gt;                &amp;lt;/div&amp;gt;&lt;br /&gt;&lt;br /&gt;                &amp;lt;!-- the dialog div we will populate if nothing is selected for edit or delete --&amp;gt;&lt;br /&gt;                &amp;lt;div id="noSelection" style="display: none;" /&amp;gt;&lt;br /&gt;              &amp;lt;/body&amp;gt;&lt;br /&gt;            &amp;lt;/html&amp;gt;&lt;br /&gt;        &lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;        All we have done here is create some global javascript variables to hold the URL values for our controller actions.&lt;br /&gt;        We could have skipped this and put all of our javascript inline but my personal preference is to keep things separated.&lt;br /&gt;        The next piece to look at is the &lt;code&gt;&amp;lt;div id="gridWrapper"&amp;gt;&lt;/code&gt;. We created an empty table to hold the jqGrid&lt;br /&gt;        and we have created a div to hold the pagination elements for the table. Pretty simple. Before we look at the javascript file&lt;br /&gt;        for this page we need to modify the &lt;code&gt;InstrumentController&lt;/code&gt; so we can return JSON data for our grid columns / rows.&lt;br /&gt;      &lt;b&gt;Modifying the Controller for the list.gsp page&lt;/b&gt;&lt;br /&gt;          Since a lot of grid list processing is the same for all controllers I have extracted the main logic into a service (covered next). There&lt;br /&gt;          are only a few modifications we need to make to our &lt;code&gt;InstrumentController&lt;/code&gt;.&lt;br /&gt;          &lt;br /&gt;&lt;br /&gt;          Add the following import to your &lt;code&gt;ImageController&lt;/code&gt;:&lt;br /&gt;          &lt;pre style="font-size: small;"&gt;&lt;br /&gt;            import grails.converters.JSON&lt;br /&gt;          &lt;/pre&gt;&lt;br /&gt;          Add the following line right under &lt;code&gt;class InstrumentController&lt;/code&gt;:&lt;br /&gt;          &lt;pre style="font-size: small;"&gt;&lt;br /&gt;            def gridService&lt;br /&gt;          &lt;/pre&gt;&lt;br /&gt;          Finally we need to add two closures for our &lt;code&gt;list&lt;/code&gt; and &lt;code&gt;edit&lt;/code&gt; process&lt;br /&gt;          &lt;pre style="font-size: small;"&gt;&lt;br /&gt;            def listJSON = {&lt;br /&gt;                // Instead of repeating this code in all controllers, all logic is handled&lt;br /&gt;                // in a service&lt;br /&gt;                render gridService.generate(params, "Instrument") as JSON&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            def editJSON = {&lt;br /&gt;                // Instead of repeating this code in all controllers, all logic is handled&lt;br /&gt;                // in a service&lt;br /&gt;                render gridService.edit(params, "Instrument") as JSON&lt;br /&gt;            }&lt;br /&gt;          &lt;/pre&gt;&lt;br /&gt;      &lt;b&gt;GridService.groovy&lt;/b&gt;&lt;br /&gt;          Since most tables (at least in this example) have the same configuration&lt;br /&gt;          for Grids all logic has been moved from Controllers to this service. The code is&lt;br /&gt;          pretty well documented so I won't really talk about what is going on.&lt;br /&gt;          &lt;pre style="font-size: small;"&gt;&lt;br /&gt;            package myband&lt;br /&gt;&lt;br /&gt;            class GridService {&lt;br /&gt;&lt;br /&gt;                // Utility service that will create a domain instance based off&lt;br /&gt;                // the short name of the object.&lt;br /&gt;                def grailsUtilService&lt;br /&gt;                def messageSource&lt;br /&gt;                boolean transactional = true&lt;br /&gt;&lt;br /&gt;                // Default closure that collects the "name" field off the results passed in&lt;br /&gt;                def defaultFields = {results -&gt;&lt;br /&gt;                    // Collect the row data for the grid&lt;br /&gt;                    def cells = results.collect {&lt;br /&gt;                        [&lt;br /&gt;                            cell: [ it.name ], // Only displaying the "Name" field&lt;br /&gt;                            id: it.id   // Always need to pass the id down for the grid&lt;br /&gt;                        ]&lt;br /&gt;                    }&lt;br /&gt;                    return cells&lt;br /&gt;                }&lt;br /&gt;&lt;br /&gt;                // Default edit closure. Used for form / inline editing, form adding and row&lt;br /&gt;                // delete&lt;br /&gt;                def defaultEdit = { instance -&gt;&lt;br /&gt;                    def result&lt;br /&gt;                    def message = ""&lt;br /&gt;                    def state = "FAIL"&lt;br /&gt;                    def id&lt;br /&gt;&lt;br /&gt;                    // determine our action. Grid will pass a param called "oper"&lt;br /&gt;                    switch (params.oper) {&lt;br /&gt;                        // Delete Request&lt;br /&gt;                        case 'del':&lt;br /&gt;                            result = instance.get(params.id)&lt;br /&gt;                            if (result) {&lt;br /&gt;                                result.delete()&lt;br /&gt;                                message = "${entity} ${result.name} Deleted"&lt;br /&gt;                                state = "OK"&lt;br /&gt;                            }&lt;br /&gt;                            break;&lt;br /&gt;                        // Add Request&lt;br /&gt;                        case 'add':&lt;br /&gt;                            instance.properties = params&lt;br /&gt;                            result = instance&lt;br /&gt;                            break;&lt;br /&gt;                        // Edit Request&lt;br /&gt;                        case 'edit':&lt;br /&gt;                            // add or edit instruction sent&lt;br /&gt;                            result = instance.get(params.id)&lt;br /&gt;                            result.properties = params&lt;br /&gt;                            break;&lt;br /&gt;                    }&lt;br /&gt;&lt;br /&gt;                    // If we aren't deleting the object then we need to validate and save.&lt;br /&gt;                    // Capture any validation messages to display on the client side&lt;br /&gt;                    if (result &amp;&amp; params.oper != "del") {&lt;br /&gt;                        if (!result.hasErrors() &amp;&amp; result.save(flush: true)) {&lt;br /&gt;                            message = "${entity}  ${result.name} " + (params.oper == 'add') ? "Added" : "Updated"&lt;br /&gt;                            id = result.id&lt;br /&gt;                            state = "OK"&lt;br /&gt;                        } else {&lt;br /&gt;                            message = "&amp;lt;ul&amp;gt;"&lt;br /&gt;                            result.errors.allErrors.each {&lt;br /&gt;                                message += "&amp;lt;li&amp;gt;${messageSource.getMessage(it)}&amp;lt;/li&amp;gt;"&lt;br /&gt;                            }&lt;br /&gt;                            message += "&amp;lt;/ul&amp;gt;"&lt;br /&gt;                        }&lt;br /&gt;                    }&lt;br /&gt;&lt;br /&gt;                    return [message:message, state:state, id:id]&lt;br /&gt;                }&lt;br /&gt;&lt;br /&gt;                /**&lt;br /&gt;                 * Generate our Grid rows/cells using the default closure and no parameters&lt;br /&gt;                 *&lt;br /&gt;                 * @param entity The Domain object shortname (no package definition)&lt;br /&gt;                 * @return The map of information that can be converted to JSON&lt;br /&gt;                 */&lt;br /&gt;                Map generate(String entity) {&lt;br /&gt;                    generate([:], entity)&lt;br /&gt;                }&lt;br /&gt;&lt;br /&gt;                /**&lt;br /&gt;                 * Generate our Grid rows/cells using the default closure and any parameters&lt;br /&gt;                 * that were passed in.&lt;br /&gt;                 *&lt;br /&gt;                 * @param params The map of parameters to use&lt;br /&gt;                 * @param entity The Domain object shortname (no package definition)&lt;br /&gt;                 * @return The map of information that can be converted to JSON&lt;br /&gt;                 */&lt;br /&gt;                Map generate(Map params, String entity) {&lt;br /&gt;                    generate(params, entity, defaultFields)&lt;br /&gt;                }&lt;br /&gt;&lt;br /&gt;                /**&lt;br /&gt;                 * Generate our Grid rows/cells using the parameters passed in. Use the supplied&lt;br /&gt;                 * closure (processor) to handle gathering the cells to display from the query&lt;br /&gt;                 * results.&lt;br /&gt;                 *&lt;br /&gt;                 * @param params The map of parameters to use&lt;br /&gt;                 * @param entity The Domain object shortname (no package definition)&lt;br /&gt;                 * @param processor The closure to use when processing query results&lt;br /&gt;                 * @return The map of information that can be converted to JSON&lt;br /&gt;                 */&lt;br /&gt;                Map generate(Map params, String entity, processor) {&lt;br /&gt;                    def result&lt;br /&gt;&lt;br /&gt;                    // The field we are sorting on&lt;br /&gt;                    def sortIndex = params.sidx ?: 'name'&lt;br /&gt;                    // The sort order&lt;br /&gt;                    def sortOrder  = params.sord ?: 'asc'&lt;br /&gt;                    // Deal with any pagination values passed in&lt;br /&gt;                    def maxRows = Integer.valueOf(params.rows ?: 25)&lt;br /&gt;                    def currentPage = Integer.valueOf(params.page ?: 1)&lt;br /&gt;                    def rowOffset = (currentPage == 1) ? 0 : (currentPage - 1) * maxRows&lt;br /&gt;&lt;br /&gt;                    // Query the datastore for the requested information&lt;br /&gt;                    def results = query(params, maxRows, rowOffset,&lt;br /&gt;                                        sortIndex, sortOrder, entity)&lt;br /&gt;&lt;br /&gt;                    // Grid needs to know the total rows and pages&lt;br /&gt;                    def totalRows = results.totalCount&lt;br /&gt;                    def numberOfPages = Math.ceil(totalRows / maxRows)&lt;br /&gt;&lt;br /&gt;                    // Call the closure to pull the rows/cells from the query results&lt;br /&gt;                    def jsonCells = processor(results)&lt;br /&gt;&lt;br /&gt;                    // Grid requires the following information to be returned&lt;br /&gt;                    [rows: jsonCells,&lt;br /&gt;                     page: currentPage,&lt;br /&gt;                     records: totalRows,&lt;br /&gt;                     total: numberOfPages]&lt;br /&gt;                }&lt;br /&gt;&lt;br /&gt;                /**&lt;br /&gt;                 * Perform editing on the object based on grid values&lt;br /&gt;                 *&lt;br /&gt;                 * @param params The map of parameters to use&lt;br /&gt;                 * @param entity The Domain object short name (no package)&lt;br /&gt;                 * @return The map of information that can be converted to JSON&lt;br /&gt;                 */&lt;br /&gt;                Map edit(Map params, String entity) {&lt;br /&gt;                    edit(params, entity, defaultEdit)&lt;br /&gt;                }&lt;br /&gt;&lt;br /&gt;                /**&lt;br /&gt;                 * Perform editing on the object based on grid values&lt;br /&gt;                 *&lt;br /&gt;                 * @param params The map of parameters to use&lt;br /&gt;                 * @param entity The Domain object short name (no package)&lt;br /&gt;                 * @param processor The closure to use for edit processing&lt;br /&gt;                 * @return The map of information that can be converted to JSON&lt;br /&gt;                 */&lt;br /&gt;                Map edit(Map params, String entity, processor) {&lt;br /&gt;                    def instance = grailsUtilService.createDomainInstance(entity)&lt;br /&gt;                    processor(instance)&lt;br /&gt;                }&lt;br /&gt;&lt;br /&gt;                /**&lt;br /&gt;                 * Queries the data store for the given object using the information passed in&lt;br /&gt;                 * ** Override this method if you want to search by things other then name&lt;br /&gt;                 *&lt;br /&gt;                 * @param params The map of parameters to use&lt;br /&gt;                 * @param maxRows The maximum number of rows to return&lt;br /&gt;                 * @param rowOffset Where we should start with the results&lt;br /&gt;                 * @param sortIndex The field we are sorting on&lt;br /&gt;                 * @param sortOrder The sorting order&lt;br /&gt;                 * @param domain The Domain object short name (no package)&lt;br /&gt;                 * @return The list of objects from the data store&lt;br /&gt;                 */&lt;br /&gt;                List query(Map params, Integer maxRows, Integer rowOffset,&lt;br /&gt;                           String sortIndex, String sortOrder, String domain) {&lt;br /&gt;                    // Stay generic and call util service to create an instance of the&lt;br /&gt;                    // domain object we are working with&lt;br /&gt;                    def instance = grailsUtilService.createDomainInstance(domain)&lt;br /&gt;                    // Perform query dealing with pagination params&lt;br /&gt;                    def results = instance.createCriteria().list(max: maxRows, offset: rowOffset) {&lt;br /&gt;                        // case insensitive, term can be anywhere&lt;br /&gt;                        if (params.name)&lt;br /&gt;                            ilike('name', '%' + params.name + '%')&lt;br /&gt;&lt;br /&gt;                        order(sortIndex, sortOrder).ignoreCase()&lt;br /&gt;                    }&lt;br /&gt;&lt;br /&gt;                    // Return the results (last statement is always the return value (unless there&lt;br /&gt;                    // is a specific return statement)&lt;br /&gt;                    results&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;          &lt;/pre&gt;&lt;br /&gt;      &lt;b&gt;GrailsUtilService.groovy&lt;/b&gt;&lt;br /&gt;        To help keep things generic we need a way to create a Domain class by name. I don't really want&lt;br /&gt;        to pass in the package name, just a short name for the domain object.&lt;br /&gt;          &lt;pre style="font-size: small;"&gt;&lt;br /&gt;            package myband&lt;br /&gt;&lt;br /&gt;            import org.codehaus.groovy.grails.commons.GrailsClass&lt;br /&gt;&lt;br /&gt;            class GrailsUtilService {&lt;br /&gt;&lt;br /&gt;                boolean transactional = false&lt;br /&gt;&lt;br /&gt;                def grailsApplication&lt;br /&gt;&lt;br /&gt;                static Map&lt;String, GrailsClass&gt; domainCache = new HashMap&lt;String, GrailsClass&gt;()&lt;br /&gt;&lt;br /&gt;                /**&lt;br /&gt;                 * Create an instance of the Domain class. Since we aren't passing in package&lt;br /&gt;                 * names we need to loop over the artefacts and find the one we are looking for.&lt;br /&gt;                 * If we were passing in package names we could just call the getDomainClass method&lt;br /&gt;                 *&lt;br /&gt;                 * @param name The short name of the Domain class we want to create&lt;br /&gt;                 * @return Instance of the requested Domain class&lt;br /&gt;                 */&lt;br /&gt;                Object createDomainInstance(String name) {&lt;br /&gt;                    if (domainCache[name])&lt;br /&gt;                        return domainCache[name].newInstance()&lt;br /&gt;&lt;br /&gt;                    def artefacts = grailsApplication.getArtefacts("Domain")&lt;br /&gt;                    def result = artefacts.find { item -&gt;&lt;br /&gt;                        item.name == name&lt;br /&gt;                    }&lt;br /&gt;&lt;br /&gt;                    if (!domainCache[name])&lt;br /&gt;                        domainCache[name] = result&lt;br /&gt;&lt;br /&gt;                    return result.newInstance()&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;          &lt;/pre&gt;&lt;br /&gt;          The javascript code to configure our grid is pretty simple. I've documented&lt;br /&gt;          things pretty well so it should pretty self explanatory.&lt;br /&gt;      &lt;b&gt;myband/web-app/js/app/instrument/list.js&lt;/b&gt;&lt;br /&gt;          &lt;pre style="font-size: small;"&gt;&lt;br /&gt;            // Use fluidGrid to handle browser resizing so the grid isn't a static width&lt;br /&gt;            function resize_the_grid() {&lt;br /&gt;                $('#instrumentGrid').fluidGrid({&lt;br /&gt;                    base:'#gridWrapper',&lt;br /&gt;                    offset: -2&lt;br /&gt;                });&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            $(document).ready(function () {&lt;br /&gt;                // when the page has finished loading.. execute the following&lt;br /&gt;                // Fade any message that may be shown&lt;br /&gt;                $('#message').show().fadeOut(5000);&lt;br /&gt;&lt;br /&gt;                // Setup our grid&lt;br /&gt;                var instrumentGrid = jQuery("#instrumentGrid").jqGrid({&lt;br /&gt;                    url: listSourceUrl,  // The URL that provides our row data&lt;br /&gt;                    editurl: listEditUrl,  // The URL to call when we submit an edit/add/delete operation&lt;br /&gt;                    datatype: "json",&lt;br /&gt;                    colNames:['Name', 'id'],  // We are only showing the Name field. Id must also be defined&lt;br /&gt;                    colModel:[&lt;br /&gt;                        {name:'name'}, // The field to pull from our JSON data for our Name column&lt;br /&gt;                        {name:'id', hidden: true} // The field to pull from our JSON data for our ID column (hidden)&lt;br /&gt;                    ],&lt;br /&gt;                    autowidth: true,&lt;br /&gt;                    sortname: 'name',  // Need to have a default sort field&lt;br /&gt;                    sortorder: 'asc',  // Need to have a default sort order&lt;br /&gt;                    scrollOffset: 0,   // Remove the screen space used for the scroll bar&lt;br /&gt;                    height: 300,       // Height of the table&lt;br /&gt;                    rowNum: 25,        // Number of rows to show&lt;br /&gt;                    rowList: [25,50,75,100],    // Values to show in dropdown for number of rows to display&lt;br /&gt;                    pager: jQuery('#instrumentGridPager'), // The element that will hold our pagination info&lt;br /&gt;                    viewrecords: true,&lt;br /&gt;                    gridview: true,&lt;br /&gt;                    ondblClickRow: function(id) {&lt;br /&gt;                        // Double Click the row to navigate to the "show" page&lt;br /&gt;                        if (id) {&lt;br /&gt;                            var url = showUrl;&lt;br /&gt;                            $(location).attr('href', url + "/" + id);&lt;br /&gt;                        }&lt;br /&gt;                    }&lt;br /&gt;                });&lt;br /&gt;&lt;br /&gt;                // jqGrid will give us a toolbar that we can add buttons to. There are default buttons&lt;br /&gt;                // but we need to tell the library which ones to display&lt;br /&gt;                $('#instrumentGrid').navGrid('#instrumentGridPager',&lt;br /&gt;                {&lt;br /&gt;                    add: false,  // Don't show the default 'add' button (form based)&lt;br /&gt;                    edit: false, // Don't show the default 'edit' button (form based)&lt;br /&gt;                    del: false,  // Don't show the default 'delete' button&lt;br /&gt;                    search: false, // Don't show the default 'search' button (form based)&lt;br /&gt;                    refresh: true // Show the 'refresh' button so we can reload data&lt;br /&gt;                });&lt;br /&gt;&lt;br /&gt;                // Add a custom 'delete' button.&lt;br /&gt;                $('#instrumentGrid').navButtonAdd('#instrumentGridPager', {&lt;br /&gt;                    caption:"",         // The caption to show (none for us)&lt;br /&gt;                    position: "first",  // The position in the toolbar for our custom button&lt;br /&gt;                    buttonicon:"ui-icon-trash", // The jquery-ui theme icon to use&lt;br /&gt;                    onClickButton:function() {&lt;br /&gt;                        // Custom javascript handler that is executed when our button is clicked&lt;br /&gt;                        // Get the row that is selected&lt;br /&gt;                        var rowid = $("#instrumentGrid").getGridParam("selrow");&lt;br /&gt;                        // User must select a row for delete to work&lt;br /&gt;                        if (rowid != null) {&lt;br /&gt;                            // Post to our controller for the delete operation&lt;br /&gt;                            $.post(listEditUrl, {id: rowid, oper: "del"}, function(data){&lt;br /&gt;                                // Server returned success so show message and set it to fade&lt;br /&gt;                                if (data.state == "OK") {&lt;br /&gt;                                    // Tell the Grid to remove the selected row from the view&lt;br /&gt;                                    $("#instrumentGrid").delRowData(rowid);&lt;br /&gt;                                    $('#message').html(data.message);&lt;br /&gt;                                    $('#message').show().fadeOut(5000);&lt;br /&gt;                                } else {&lt;br /&gt;                                    // Server reported failure. Show message and set to fade&lt;br /&gt;                                    $('#message').html(data.message);&lt;br /&gt;                                    $('#message').show().fadeOut(10000);&lt;br /&gt;                                }&lt;br /&gt;                            });&lt;br /&gt;                        } else {&lt;br /&gt;                            // User did not select a row. Show a dialog telling them what is wrong&lt;br /&gt;                            $("#noSelection").html("You must select a row to delete.");&lt;br /&gt;                            $("#noSelection").dialog({&lt;br /&gt;                                modal: true,&lt;br /&gt;                                title: "Invalid Selection"&lt;br /&gt;                            });&lt;br /&gt;                        }&lt;br /&gt;                    }&lt;br /&gt;                });&lt;br /&gt;&lt;br /&gt;                // Create a custom 'edit' button in our toolbar&lt;br /&gt;                $('#instrumentGrid').navButtonAdd('#instrumentGridPager', {&lt;br /&gt;                    caption:"",  // No caption for this&lt;br /&gt;                    position: "first", // Make first in list&lt;br /&gt;                    buttonicon:"ui-icon-pencil", // Use the pencil icon from the theme&lt;br /&gt;                    onClickButton:function() {&lt;br /&gt;                        // Get selected row&lt;br /&gt;                        var rowid = $("#instrumentGrid").getGridParam("selrow");&lt;br /&gt;                        // Must select a row to edit&lt;br /&gt;                        if (rowid != null) {&lt;br /&gt;                            // direct browser to our 'edit' page&lt;br /&gt;                            $(location).attr('href', editUrl + "/" + rowid);&lt;br /&gt;                        } else {&lt;br /&gt;                            // No row selected, can't edit. Show a dialog&lt;br /&gt;                            $("#noSelection").html("You must select a row to edit.");&lt;br /&gt;                            $("#noSelection").dialog({&lt;br /&gt;                                modal: true,&lt;br /&gt;                                title: "Invalid Selection"&lt;br /&gt;                            });&lt;br /&gt;                        }&lt;br /&gt;                    }&lt;br /&gt;                });&lt;br /&gt;&lt;br /&gt;                // Create a custom 'add' button for the toolbar&lt;br /&gt;                $('#instrumentGrid').navButtonAdd('#instrumentGridPager', {&lt;br /&gt;                    caption:"", // No caption&lt;br /&gt;                    position: "first", // First in list&lt;br /&gt;                    buttonicon:"ui-icon-plus", // use the 'plus' icon from the theme&lt;br /&gt;                    onClickButton:function() {&lt;br /&gt;                        // direct browser to our 'create' page&lt;br /&gt;                        $(location).attr('href', createUrl);&lt;br /&gt;                    }&lt;br /&gt;                });&lt;br /&gt;&lt;br /&gt;                // Create a custom 'search' button for the toolbar&lt;br /&gt;                $('#instrumentGrid').navButtonAdd('#instrumentGridPager', {&lt;br /&gt;                    caption:"", // No caption&lt;br /&gt;                    buttonicon:"ui-icon-search", // use the 'search' icon from the theme&lt;br /&gt;                    onClickButton:function() {&lt;br /&gt;                        // We are doing inline search/filtering so when the user clicks&lt;br /&gt;                        // search either display or hide the filter/search row&lt;br /&gt;                        instrumentGrid[0].toggleToolbar();&lt;br /&gt;                    }&lt;br /&gt;                });&lt;br /&gt;&lt;br /&gt;                // jqGrid allows for inline searching/filtering. Configure filter row to work&lt;br /&gt;                // like autocomplete&lt;br /&gt;                $('#instrumentGrid').filterToolbar({&lt;br /&gt;                    autosearch: true,&lt;br /&gt;                    searchOnEnter: false&lt;br /&gt;                });&lt;br /&gt;            });&lt;br /&gt;&lt;br /&gt;            // Resize the grid when the browser is resized&lt;br /&gt;            $(window).resize(resize_the_grid);&lt;br /&gt;          &lt;/pre&gt;&lt;br /&gt;          At this point our list page for Instrument is done. A good amount of code,&lt;br /&gt;          not excessive but still a good amount. Nothing really complicated, just&lt;br /&gt;          a mixture of both client and server-side logic. We will go through&lt;br /&gt;          adding Formular to our edit / create page next so we have a full stripe&lt;br /&gt;          complete.&lt;br /&gt;&lt;br /&gt;      &lt;b&gt;Form validation with Formular&lt;/b&gt;&lt;br /&gt;          Formular is a nice little library that handles real-time client-side validation.&lt;br /&gt;          There are no annoying javascript popups, just simple tooltips that let the user&lt;br /&gt;          know what is wrong.&lt;br /&gt;          For the Instrument create/edit pages we only have a few rules to follow&lt;br /&gt;          when it comes to client-side validation. We want to ensure the following&lt;br /&gt;          for the "Name" field:&lt;br /&gt;          &lt;pre&gt;&lt;br /&gt;              Required&lt;br /&gt;              More then 4 Characters&lt;br /&gt;              Only alphabetic characters and spaces allowed&lt;br /&gt;          &lt;/pre&gt;&lt;br /&gt;          To use Formular we don't need todo anything to our edit/create pages except&lt;br /&gt;          add the required javascript libraries and css files. You can find the edit.gsp&lt;br /&gt;          and create.gsp in the source download for this post. We will take a look&lt;br /&gt;          at the javascript needed to make everything work.&lt;br /&gt;&lt;br /&gt;          The instrument validation.js file holds the client side validation rules we want&lt;br /&gt;          to apply.&lt;br /&gt;          &lt;b&gt;myband/web-app/js/app/instrument/validation.js&lt;/b&gt;&lt;br /&gt;          &lt;pre style="font-size: small;"&gt;&lt;br /&gt;            $(document).ready(function() {&lt;br /&gt;                // Create the validator for our form&lt;br /&gt;                var formular = $("#form").formValidator({&lt;br /&gt;                    forms: {&lt;br /&gt;                        // Validate the name field&lt;br /&gt;                        name: {&lt;br /&gt;                            // The validation rules&lt;br /&gt;                            rules: {&lt;br /&gt;                                required: true, // Do required check&lt;br /&gt;                                lengthMin: 4,   // Do length check&lt;br /&gt;                                regEx: /^[A-Za-z ]+$/ // Do alpha and space check.&lt;br /&gt;                                                      // Not a very good regex pattern but shows concept&lt;br /&gt;                            },&lt;br /&gt;                            // The messages to show (name of message must match validation rule&lt;br /&gt;                            msg: {&lt;br /&gt;                                required: "Name is required",&lt;br /&gt;                                lengthMin: "Name must be at least 4 characters long",&lt;br /&gt;                                regEx: "Only alphabetic and spaces are allowed"&lt;br /&gt;                            }&lt;br /&gt;                        }&lt;br /&gt;                    },&lt;br /&gt;                    validateLive: true,&lt;br /&gt;                    validateOn: "",     // Hide some content formular puts on the page&lt;br /&gt;                    validateOff: "",    // Hide some content formular puts on the page&lt;br /&gt;                    submitHowTo: "post",    // Formular will submit the form if everything passes&lt;br /&gt;                    submitUrl: validationUrl,   // The URL to submit the form values to&lt;br /&gt;                    customError: customError    // We are showing tooltips next to fields, define handler&lt;br /&gt;                })&lt;br /&gt;            });&lt;br /&gt;          &lt;/pre&gt;&lt;br /&gt;          The app validation.js file holds the custom error handler we use to show&lt;br /&gt;          tooltips next to fields in error.&lt;br /&gt;          &lt;b&gt;myband/web-app/js/app/validation.js&lt;/b&gt;&lt;br /&gt;          &lt;pre style="font-size: small;"&gt;&lt;br /&gt;            var customError = function(event, data){&lt;br /&gt;                // Iterate over any errors we may have and show if needed&lt;br /&gt;                for (var error in data["errors"]){&lt;br /&gt;                    // New error, show tooltip with message&lt;br /&gt;                    if (data.errors[error] == "new") {&lt;br /&gt;                        // did we already set a tooltip?&lt;br /&gt;                        if (!data.tooltip) {&lt;br /&gt;                            // If the field we are validating is hidden (maybe library like multiselect)&lt;br /&gt;                            // then we need to make it visible so we can calculate tooltip location&lt;br /&gt;                            var vis = data.element.is(":visible");&lt;br /&gt;                            if (!vis)&lt;br /&gt;                                data.element.show();&lt;br /&gt;&lt;br /&gt;                            // we need to check for a context which is not a checkbox so we use to the parent element (which is div.pair)&lt;br /&gt;                            var selector = (data.type == "group") ? data.element.first().parent() : data.element; // jquery 1.4.x&lt;br /&gt;&lt;br /&gt;                            data.tooltip = selector.tooltip({&lt;br /&gt;                                content: function() {&lt;br /&gt;                                    // use the error message&lt;br /&gt;                                    return data.msg[error];&lt;br /&gt;                                },&lt;br /&gt;                                // ui.position settings&lt;br /&gt;                                position: {&lt;br /&gt;                                    my: "left top",&lt;br /&gt;                                    at: "right top",&lt;br /&gt;                                    offset: "35 0",&lt;br /&gt;                                    of: selector&lt;br /&gt;                                },&lt;br /&gt;                                tooltipClass: "ui-widget-content",&lt;br /&gt;                                noHover: true&lt;br /&gt;                            });&lt;br /&gt;                            // Show tooltip next to the element&lt;br /&gt;                            data.tooltip.tooltip("open", selector);&lt;br /&gt;                            // We may have shown a hidden element so we could get position info&lt;br /&gt;                            // Hide it now if it was hidden before&lt;br /&gt;                            if (!vis)&lt;br /&gt;                                data.element.hide();&lt;br /&gt;&lt;br /&gt;                        }&lt;br /&gt;                    } else if (data.errors[error] == "corrected") {&lt;br /&gt;                        // Close the tooltip, validation error was corrected&lt;br /&gt;                        data.tooltip.tooltip("close");&lt;br /&gt;                        data.tooltip.tooltip("destroy");&lt;br /&gt;                        data.tooltip = false;&lt;br /&gt;                    }&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;          &lt;/pre&gt;&lt;br /&gt;      Ok, that about does it for this post. We've got a jqGrid working, Formular&lt;br /&gt;      validation working and everything is using jquery-ui themes. Not to bad. I'll&lt;br /&gt;      introduce a few more components in the next post.&lt;br /&gt;      &lt;b&gt;Resources&lt;/b&gt;&lt;br /&gt;      &lt;div&gt;&lt;br /&gt;        Source: &lt;a href="http://sites.google.com/site/aoathout/myband-part3.zip"&gt;Grails Tutorial - Part 3&lt;/a&gt;&lt;br /&gt;        &amp;nbsp;&amp;nbsp;&lt;span style="color: red; font-size: small;"&gt;** After downloading, rename the folder to "myband".&lt;/span&gt;&lt;br /&gt;        Grails: &lt;a href="http://www.grails.org/"&gt;http://www.grails.org&lt;/a&gt;&lt;br /&gt;        jQuery: &lt;a href="http://jquery.com/"&gt;http://jquery.com&lt;/a&gt;&lt;br /&gt;        jQuery UI: &lt;a href="http://jqueryui.com/"&gt;http://jqueryui.com&lt;/a&gt;&lt;br /&gt;        jqGrid: &lt;a href="http://www.trirand.com/blog"&gt;http://www.trirand.com/blog&lt;/a&gt;&lt;br /&gt;        fgMenu: &lt;a href="http://www.filamentgroup.com/lab/jquery_ipod_style_and_flyout_menus/"&gt;http://www.filamentgroup.com/lab/jquery_ipod_style_and_flyout_menus&lt;/a&gt;&lt;br /&gt;        Multi-Select List: &lt;a href="http://quasipartikel.at/multiselect/"&gt;http://quasipartikel.at/multiselect/&lt;/a&gt;&lt;br /&gt;        Formular: &lt;a href="http://wiki.github.com/fnagel/jQuery-Accessible-RIA/formular"&gt;http://wiki.github.com/fnagel/jQuery-Accessible-RIA/formular&lt;/a&gt;&lt;br /&gt;        Git: &lt;a href="http://git-scm.com/"&gt;http://git-scm.com&lt;/a&gt;&lt;br /&gt;      &lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3498211330006616408-6778699305765881610?l=aoathout.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aoathout.blogspot.com/feeds/6778699305765881610/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://aoathout.blogspot.com/2010/07/grails-tutorial-part-3.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3498211330006616408/posts/default/6778699305765881610'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3498211330006616408/posts/default/6778699305765881610'/><link rel='alternate' type='text/html' href='http://aoathout.blogspot.com/2010/07/grails-tutorial-part-3.html' title='Grails Tutorial - Part 3'/><author><name>Aaron Oathout</name><uri>http://www.blogger.com/profile/17544558400157608670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3498211330006616408.post-3909674778310601642</id><published>2010-07-10T23:33:00.002-05:00</published><updated>2010-07-10T23:35:03.219-05:00</updated><title type='text'>Next Post Soon</title><content type='html'>I have been very busy with the day job (JSF/Liferay, not so fun). The code for the next post has been done for a very long time. Just need to document it and write the content.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3498211330006616408-3909674778310601642?l=aoathout.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aoathout.blogspot.com/feeds/3909674778310601642/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://aoathout.blogspot.com/2010/07/next-post-soon.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3498211330006616408/posts/default/3909674778310601642'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3498211330006616408/posts/default/3909674778310601642'/><link rel='alternate' type='text/html' href='http://aoathout.blogspot.com/2010/07/next-post-soon.html' title='Next Post Soon'/><author><name>Aaron Oathout</name><uri>http://www.blogger.com/profile/17544558400157608670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3498211330006616408.post-5261866319667790488</id><published>2010-06-24T23:15:00.000-05:00</published><updated>2010-06-24T23:18:02.579-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='jquery'/><category scheme='http://www.blogger.com/atom/ns#' term='jqueryui'/><category scheme='http://www.blogger.com/atom/ns#' term='jqgrid'/><category scheme='http://www.blogger.com/atom/ns#' term='grails'/><title type='text'>Grails Tutorial - Part 2</title><content type='html'>In the first post we covered creating our Project and local Git&lt;br /&gt;&lt;div&gt;            repository. We created our Domain objects and generated all of the&lt;br /&gt;          Controllers and views. At this point we have written very little&lt;br /&gt;          code and we have a working application. As stated in my comment on&lt;br /&gt;          the blog I have since upgraded things to grails 1.3.2. To upgrade&lt;br /&gt;          the code simply download grails 1.3.2, set your path and type&lt;br /&gt;          &lt;span style="font-size:small;"&gt;grails upgrade&lt;/span&gt; in the&lt;br /&gt;          &lt;span style="font-size:small;"&gt;myband&lt;/span&gt; folder. That's it.&lt;br /&gt;          Easy upgrade.&lt;br /&gt;        &lt;br /&gt;          In this post we will change the main layout, add some style sheets,&lt;br /&gt;          add jquery / jquery-ui javascript libraries and add the ThemeSwitcher.&lt;br /&gt;        &lt;br /&gt;          &lt;b&gt;Changing the main layout&lt;/b&gt;&lt;br /&gt;          Grails uses &lt;a href="http://www.opensymphony.com/sitemesh/"&gt;SiteMesh&lt;/a&gt;&lt;br /&gt;          for layout and decoration. This makes things dead simple. Simply&lt;br /&gt;          change the &lt;code&gt;myband/grails-app/views/layouts/main.gsp&lt;/code&gt; file.&lt;br /&gt;          There are also some CSS changes to make for the site.&lt;br /&gt;          All the files are listed below&lt;br /&gt;      &lt;/div&gt;&lt;br /&gt;      &lt;div style="font-size: small;"&gt;myband/grails-app/views/layouts/main.gsp&lt;/div&gt;&lt;div&gt;&lt;pre style="font-size: small;"&gt;&lt;br /&gt;      &amp;lt;!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"&lt;br /&gt;            "http://www.w3.org/TR/html4/strict.dtd"&amp;gt;&lt;br /&gt;          &amp;lt;html&amp;gt;&lt;br /&gt;            &amp;lt;head&amp;gt;&lt;br /&gt;              &amp;lt;meta http-equiv="PRAGMA" content="NO-CACHE"&amp;gt;&lt;br /&gt;              &amp;lt;meta http-equiv="CACHE-CONTROL" content="NO-CACHE"&amp;gt;&lt;br /&gt;              &amp;lt;meta http-equiv="EXPIRES" content="Mon, 22 Jul 2002 11:12:01 GMT"&amp;gt;&lt;br /&gt;              &amp;lt;meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /&amp;gt;&lt;br /&gt;&lt;br /&gt;              &amp;lt;title&amp;gt;&amp;lt;g:layoutTitle default="MyBand" /&amp;gt;&amp;lt;/title&amp;gt;&lt;br /&gt;              &amp;lt;link rel="stylesheet" href="${resource(dir:'css/theme', file:'jquery-ui-1.8.2.custom.css')}" /&amp;gt;&lt;br /&gt;              &amp;lt;link rel="stylesheet" href="${resource(dir:'css/menu', file:'fg.menu.css')}" /&amp;gt;&lt;br /&gt;              &amp;lt;link rel="stylesheet" href="${resource(dir:'css', file:'main.css')}" /&amp;gt;&lt;br /&gt;              &amp;lt;link rel="stylesheet" href="${resource(dir:'css', file:'site.css')}" /&amp;gt;&lt;br /&gt;              &amp;lt;link rel="stylesheet" href="${resource(dir:'css', file:'messages.css')}" /&amp;gt;&lt;br /&gt;              &amp;lt;g:javascript library="menu/fg.menu" /&amp;gt;&lt;br /&gt;&lt;br /&gt;              &amp;lt;g:javascript library="app/application" /&amp;gt;&lt;br /&gt;&lt;br /&gt;              &amp;lt;g:layoutHead /&amp;gt;&lt;br /&gt;&lt;br /&gt;          &amp;lt;/head&amp;gt;&lt;br /&gt;          &amp;lt;body class="ui-widget-content"&amp;gt;&lt;br /&gt;            &amp;lt;div&amp;gt;&lt;br /&gt;              &amp;lt;div id="header" class="ui-widget-header"&amp;gt;&lt;br /&gt;                &amp;lt;!-- Generally would include the header section --&amp;gt;&lt;br /&gt;              &amp;lt;/div&amp;gt;&lt;br /&gt;        &lt;br /&gt;              &amp;lt;!-- Include the menu definitions. --&amp;gt;&lt;br /&gt;              &amp;lt;g:render template="/layouts/includes/menu"/&amp;gt;&lt;br /&gt;        &lt;br /&gt;              &amp;lt;!-- Theme Switcher Component will show here --&amp;gt;&lt;br /&gt;              &amp;lt;div id="switcher" style="margin-top: 5px;"&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;        &lt;br /&gt;              &amp;lt;div id="bodyContent"&amp;gt;&lt;br /&gt;                &amp;lt;div id="sidebar"&amp;gt;&lt;br /&gt;                  &amp;lt;!-- Include the accordion sidenav --&amp;gt;&lt;br /&gt;                  &amp;lt;g:render template="/layouts/includes/leftnav" /&amp;gt;&lt;br /&gt;                &amp;lt;/div&amp;gt;&lt;br /&gt;        &lt;br /&gt;                &amp;lt;div id="main"&amp;gt;&lt;br /&gt;                  &amp;lt;g:layoutBody/&amp;gt;&lt;br /&gt;                &amp;lt;/div&amp;gt;&lt;br /&gt;              &amp;lt;/div&amp;gt;&lt;br /&gt;        &lt;br /&gt;              &amp;lt;!-- Footer that always shows at bottom of page --&amp;gt;&lt;br /&gt;              &amp;lt;div id="footer" class="ui-widget-header"&amp;gt;&lt;br /&gt;                  &amp;lt;div id="footerContent"&amp;gt;&lt;br /&gt;                    MyBand &amp;lt;g:meta name="app.version"/&amp;gt; on Grails &amp;lt;g:meta name="app.grails.version" /&amp;gt;.&lt;br /&gt;                  &amp;lt;/div&amp;gt;&lt;br /&gt;              &amp;lt;/div&amp;gt;&lt;br /&gt;            &amp;lt;/div&amp;gt;&lt;br /&gt;          &amp;lt;/body&amp;gt;&lt;br /&gt;        &amp;lt;/html&amp;gt;&lt;br /&gt;  &lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;Im including two gsp template files that hold the menu links and&lt;br /&gt;&lt;div&gt;            the sidebar links. The contents of both files are listed below&lt;br /&gt;      &lt;/div&gt;&lt;br /&gt;      &lt;div style="font-size: small;"&gt;myband/grails-app/views/layouts/includes/_menu.gsp&lt;/div&gt;&lt;div&gt;&lt;pre style="font-size: small;"&gt;&lt;br /&gt;      &amp;lt;div id="nav" class="ui-widget-header ui-corner-all"&amp;gt;&lt;br /&gt;        &amp;lt;a class="ui-widget-header ui-corner-all" href="${createLinkTo(url: '/')}" id="homeMenu"&amp;gt;Home&amp;lt;/a&amp;gt;&lt;br /&gt;        &amp;lt;a class="ui-widget-header ui-corner-all" href="#" id="bandMenu"&amp;gt;Band&amp;lt;/a&amp;gt;&lt;br /&gt;        &amp;lt;a class="ui-widget-header ui-corner-all" href="#" id="gigMenu"&amp;gt;Gig&amp;lt;/a&amp;gt;&lt;br /&gt;        &amp;lt;a class="ui-widget-header ui-corner-all" href="#" id="adminMenu"&amp;gt;Admin&amp;lt;/a&amp;gt;&lt;br /&gt;      &amp;lt;/div&amp;gt;&lt;br /&gt;&lt;br /&gt;      &amp;lt;div id="bandMenuContent" style="display:none;"&amp;gt;&lt;br /&gt;        &amp;lt;ul&amp;gt;&lt;br /&gt;            &amp;lt;li style="height: 15;"&amp;gt;&amp;lt;a href="${createLink(controller: 'band')}"&amp;gt;Band Information&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;            &amp;lt;li style="height: 15;"&amp;gt;&amp;lt;a href="${createLink(controller: 'member')}"&amp;gt;Band Members&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;            &amp;lt;li style="height: 15;"&amp;gt;&amp;lt;a href="${createLink(controller: 'song')}"&amp;gt;Songs&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;        &amp;lt;/ul&amp;gt;&lt;br /&gt;      &amp;lt;/div&amp;gt;&lt;br /&gt;&lt;br /&gt;      &amp;lt;div id="gigMenuContent" style="display:none;"&amp;gt;&lt;br /&gt;        &amp;lt;ul&amp;gt;&lt;br /&gt;          &amp;lt;li&amp;gt;&amp;lt;a href="${createLink(controller: 'gig')}"&amp;gt;Gig Information&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;          &amp;lt;li&amp;gt;&amp;lt;a href="${createLink(controller: 'setList')}"&amp;gt;Set Lists&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;        &amp;lt;/ul&amp;gt;&lt;br /&gt;      &amp;lt;/div&amp;gt;&lt;br /&gt;&lt;br /&gt;      &amp;lt;div id="adminMenuContent" style="display:none;"&amp;gt;&lt;br /&gt;        &amp;lt;ul&amp;gt;&lt;br /&gt;          &amp;lt;li&amp;gt;&amp;lt;a href="${createLink(controller: 'instrument')}"&amp;gt;Instruments&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;        &amp;lt;/ul&amp;gt;&lt;br /&gt;      &amp;lt;/div&amp;gt;&lt;br /&gt;  &lt;/pre&gt;&lt;/div&gt;&lt;div&gt;            Notice the style definitions for the anchors. When running in IE8&lt;br /&gt;          the menu code will not work unless it can pull height and width. (at&lt;br /&gt;          least that is what I have observed on my Win7 VM)&lt;br /&gt;      &lt;/div&gt;&lt;br /&gt;      &lt;div style="font-size: small;"&gt;myband/grails-app/views/layouts/includes/_leftnav.gsp&lt;/div&gt;&lt;div&gt;&lt;pre style="font-size: small;"&gt;&lt;br /&gt;      &amp;lt;div id="leftnav"&amp;gt;&lt;br /&gt;        &amp;lt;h3&amp;gt;&amp;lt;a href="#"&amp;gt;What would you like todo?&amp;lt;/a&amp;gt;&amp;lt;/h3&amp;gt;&lt;br /&gt;        &amp;lt;div&amp;gt;&lt;br /&gt;          &amp;lt;a href="${createLink(controller: 'band')}"&amp;gt;View My Bands&amp;lt;/a&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;          &amp;lt;a href="${createLink(controller: 'member')}"&amp;gt;View Band Members&amp;lt;/a&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;          &amp;lt;a href="${createLink(controller: 'song')}"&amp;gt;View Songs&amp;lt;/a&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;          &amp;lt;a href="${createLink(controller: 'gig')}"&amp;gt;View Gigs&amp;lt;/a&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;          &amp;lt;a href="${createLink(controller: 'setList')}"&amp;gt;View Set Lists&amp;lt;/a&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;        &amp;lt;/div&amp;gt;&lt;br /&gt;      &amp;lt;/div&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;        &lt;div&gt;&lt;br /&gt;          The details of using the two included templates will be shown later.&lt;br /&gt;          The style sheets being used can be found in the source code download&lt;br /&gt;          in the Resources section. (You will need some of the javascript libraries&lt;br /&gt;          from the source code later in this post)&lt;br /&gt;      &lt;/div&gt;&lt;br /&gt;      This doesn't give us much more then a basic layou. This will change as we add more components. The important things to take from this section is the "ui-widget-*" classes.&lt;br /&gt;      These are jQueryUI css/theme items. Adding these allows us to change the&lt;br /&gt;      full site look-n-feel.&lt;br /&gt;&lt;br /&gt;      &lt;div&gt;&lt;b&gt;Adding jQuery and jQuery UI&lt;/b&gt;&lt;/div&gt;There are currently two Grails plugins to help with adding jQuery and&lt;br /&gt;&lt;div&gt;                jQuery UI javascript to projects. You can find them on the main Grails&lt;br /&gt;              plugins page. We will just download and use the standard javascript&lt;br /&gt;              files for this app. (&lt;span style="font-size:small;"&gt;Trying to keep&lt;br /&gt;              dependencies down and people may have a certain version of jquery /&lt;br /&gt;              jquery-ui they need to use&lt;/span&gt;)&lt;br /&gt;          &lt;/div&gt;&lt;br /&gt;Create a "jquery" and "jquery-ui" directory in your&lt;br /&gt;&lt;div&gt;                &lt;span style="font-size:small;"&gt;myband/web-app/js&lt;/span&gt; directory.&lt;br /&gt;              Download the library files if you don't already have a copy.&lt;br /&gt;              (&lt;span style="font-size:small;"&gt;See the &lt;/span&gt; Resources section&lt;br /&gt;              for site urls). I'm using jquery 1.4.2 and jquery-ui 1.8.2 for&lt;br /&gt;              this project.&lt;br /&gt;          &lt;/div&gt;&lt;br /&gt;Once everything is download and installed, modify your&lt;br /&gt;&lt;div&gt;                &lt;span style="font-size:small;"&gt;myband/grails-app/views/layouts/main.gsp&lt;/span&gt;&lt;br /&gt;              file so it includes the following code before the&lt;br /&gt;              &lt;span style="font-size:small;"&gt;&amp;lt;g:layouthead&amp;gt;&lt;/span&gt; tag&lt;br /&gt;          &lt;/div&gt;&lt;div&gt;&lt;pre style="font-size: small;"&gt;&lt;br /&gt;          &amp;lt;g:javascript library="jquery/jquery-1.4.2"/&amp;gt;&lt;br /&gt;          &amp;lt;g:javascript library="jquery-ui/jquery.ui.core"/&amp;gt;&lt;br /&gt;          &amp;lt;g:javascript library="jquery-ui/jquery.ui.widget"/&amp;gt;&lt;br /&gt;          &amp;lt;g:javascript library="jquery-ui/jquery.ui.mouse"/&amp;gt;&lt;br /&gt;          &amp;lt;g:javascript library="jquery-ui/jquery.ui.button"/&amp;gt;&lt;br /&gt;          &amp;lt;g:javascript library="jquery-ui/jquery.ui.position"/&amp;gt;&lt;br /&gt;          &amp;lt;g:javascript library="jquery-ui/jquery.ui.draggable"/&amp;gt;&lt;br /&gt;          &amp;lt;g:javascript library="jquery-ui/jquery.ui.dialog"/&amp;gt;&lt;br /&gt;          &amp;lt;g:javascript library="jquery-ui/jquery.ui.autocomplete"/&amp;gt;&lt;br /&gt;          &amp;lt;g:javascript library="jquery-ui/jquery.ui.accordion"/&amp;gt;&lt;br /&gt;   &lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;The jQuery UI &lt;a href="http://jqueryui.com/docs/Theming/ThemeSwitcher"&gt;ThemeSwitcher&lt;/a&gt;&lt;br /&gt;&lt;div&gt;                is a nice little component that will allow us to change the&lt;br /&gt;              look and feel of our site using packaged themes from&lt;br /&gt;              &lt;a href="http://jqueryui.com/themeroller/"&gt;ThemeRoller&lt;/a&gt;.  To&lt;br /&gt;              add this to the site there are two things we have to-do.&lt;br /&gt;          &lt;/div&gt;&lt;br /&gt;Modify &lt;span style="font-size:small;"&gt;myband/grails-app/views/layouts/main.gsp&lt;/span&gt;.&lt;br /&gt;&lt;div&gt;                Add the following before the &lt;code style="font-size: small;"&gt;&amp;lt;g:layouthead&amp;gt;&lt;/code&gt; tag&lt;/div&gt;&lt;div&gt;&lt;pre style="font-size: small;"&gt;&lt;br /&gt;      &amp;lt;script type="text/javascript" src="http://jqueryui.com/themeroller/themeswitchertool/"&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;  &lt;/pre&gt;&lt;/div&gt;Change your &lt;span style="font-size:small;"&gt;myband/web-app/js/app/application.js&lt;/span&gt;so it only has the following&lt;br /&gt;&lt;div&gt;&lt;pre style="font-size: small;"&gt;&lt;br /&gt;          $(document).ready(function () {&lt;br /&gt;              $('#switcher').themeswitcher();&lt;br /&gt;          });&lt;br /&gt;  &lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;Pretty simple. Once we have the menu and accordion components in&lt;br /&gt;&lt;div&gt;                place you will see the beauty of the theme switcher component.&lt;br /&gt;          &lt;/div&gt;&lt;br /&gt;          &lt;div&gt;&lt;b&gt;Adding the Menu (fgMenu)&lt;/b&gt;&lt;/div&gt;Every site needs a menu. This will be no different. I've choose&lt;br /&gt;&lt;div&gt;                a menu from the &lt;a href="http://www.filamentgroup.com/lab/jquery_ipod_style_and_flyout_menus/"&gt;&lt;br /&gt;                  Filament Group&lt;br /&gt;              &lt;/a&gt;. According to the filament group site and the jQuery UI site&lt;br /&gt;              the code has been donated to jQuery UI and may (should) become&lt;br /&gt;              part of jQuery UI core.&lt;br /&gt;&lt;br /&gt;              The main.gsp file and _menu.gsp files took care of defining our&lt;br /&gt;              menu content. The only thing left to-do is add the javascript&lt;br /&gt;              to make the menu work. For this we will add a menu.js file. The&lt;br /&gt;              contents of that file are listed below&lt;br /&gt;          &lt;/div&gt;&lt;br /&gt;          &lt;div style="font-size: small;"&gt;myband/web-app/js/app/menu.js&lt;/div&gt;&lt;div&gt;&lt;pre style="font-size: small;"&gt;&lt;br /&gt;  /*&lt;br /&gt;   * Provides all the javascript / jquery code for our top flyout menu&lt;br /&gt;   */&lt;br /&gt;  $(document).ready(function() {&lt;br /&gt;      // Original fg menu script calls component Menu. This causes issues with other&lt;br /&gt;      // jQuery UI components. I renamed to fgMenu. Search the script for "fgMenu"&lt;br /&gt;      // to see what I have changed.&lt;br /&gt;&lt;br /&gt;      // Band Menu&lt;br /&gt;      $('#bandMenu').fgMenu({&lt;br /&gt;          content: $("#bandMenuContent").html(),&lt;br /&gt;          flyOut: true,&lt;br /&gt;          width: 200,&lt;br /&gt;          maxHeight: 200&lt;br /&gt;      });&lt;br /&gt;      /* If you need to dynamically create the menu you can call a controller&lt;br /&gt;       * that will return the data for you (in html or build a json parser for the&lt;br /&gt;       * menu. Example code for calling ajax service is below&lt;br /&gt;&lt;br /&gt;      // bandMenuUrl would be the URL of the correct action on a Controller&lt;br /&gt;      // If you want to use createLink() then you can create a global javascript&lt;br /&gt;      // variable in your gsp view that is assigned the output of createLink()&lt;br /&gt;      $.get(bandMenuUrl,&lt;br /&gt;          function(data){&lt;br /&gt;              // grab content from another page&lt;br /&gt;              $('#bandMenu').fgMenu({&lt;br /&gt;                  content: data,&lt;br /&gt;                  flyOut: true,&lt;br /&gt;                  width: 200,&lt;br /&gt;                  maxHeight: 200&lt;br /&gt;              });&lt;br /&gt;          });&lt;br /&gt;      */&lt;br /&gt;&lt;br /&gt;      // Gig Menu&lt;br /&gt;      $('#gigMenu').fgMenu({&lt;br /&gt;          content: $("#gigMenuContent").html(),&lt;br /&gt;          flyOut: true,&lt;br /&gt;          width: 200,&lt;br /&gt;          maxHeight: 200&lt;br /&gt;      });&lt;br /&gt;&lt;br /&gt;      // Admin Menu&lt;br /&gt;      $('#adminMenu').fgMenu({&lt;br /&gt;          content: $("#adminMenuContent").html(),&lt;br /&gt;          flyOut: true,&lt;br /&gt;          width: 200,&lt;br /&gt;          maxHeight: 200&lt;br /&gt;      });&lt;br /&gt;&lt;br /&gt;  });&lt;br /&gt;  &lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;            &lt;div&gt;&lt;b&gt;Adding the SideBar (Accordion)&lt;/b&gt;&lt;/div&gt;The accordion is one of the easiest widgets to use. Just for fun&lt;br /&gt;&lt;div&gt;                we will add one for the sidenav div. The main.gsp and _leftnav.gsp&lt;br /&gt;              files took care of adding the content, we just need to add some&lt;br /&gt;              javascript. The modified application.js file is below&lt;br /&gt;          &lt;/div&gt;&lt;div&gt;&lt;pre style="font-size: small;"&gt;&lt;br /&gt;$(document).ready(function () {&lt;br /&gt;  $('#switcher').themeswitcher();&lt;br /&gt;  $("#leftnav").accordion({&lt;br /&gt;      fillSpace: true&lt;br /&gt;  });&lt;br /&gt;});&lt;br /&gt;  &lt;/pre&gt;&lt;/div&gt;            &lt;div&gt;&lt;b&gt;Changing the main index page&lt;/b&gt;&lt;div&gt;So we don't want our users to see the list of controllers and&lt;br /&gt;&lt;div&gt;                plugins that we are using. We aren't going to create anything&lt;br /&gt;              fancy, just something functional (this is just an example).&lt;br /&gt;          &lt;/div&gt;&lt;div&gt;&lt;pre style="font-size: small;"&gt;&lt;br /&gt;      &amp;lt;html&amp;gt;&lt;br /&gt;        &amp;lt;head&amp;gt;&lt;br /&gt;          &amp;lt;meta name="layout" content="main" /&amp;gt;&lt;br /&gt;        &amp;lt;/head&amp;gt;&lt;br /&gt;        &amp;lt;body&amp;gt;&lt;br /&gt;          &amp;lt;div class="ui-widget-content ui-corner-all"&amp;gt;&lt;br /&gt;            &amp;lt;h3 class="ui-widget-header ui-corner-all" style="text-align: center;"&amp;gt;&lt;br /&gt;               Welcome to MyBand&lt;br /&gt;            &amp;lt;/h3&amp;gt;&lt;br /&gt;            &amp;lt;p&amp;gt;&lt;br /&gt;                MyBand is a site that will help you keep track of you Bands. You can keep track&lt;br /&gt;                of who is in the band and what instruments they play. You can also keep track of&lt;br /&gt;                the songs your band has. &amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;&lt;br /&gt;                When it comes to Gigs we've got you covered.&lt;br /&gt;                Keep track of when and where you are playing. Create set lists from songs&lt;br /&gt;                you have stored.&lt;br /&gt;            &amp;lt;/p&amp;gt;&lt;br /&gt;          &amp;lt;/div&amp;gt;&lt;br /&gt;        &amp;lt;/body&amp;gt;&lt;br /&gt;      &amp;lt;/html&amp;gt;&lt;br /&gt;  &lt;/pre&gt;Ok. We didn't really use any grails in this post. Basically alllayout and prep work for the rest of the app. The next post will&lt;br /&gt;&lt;/div&gt;&lt;div&gt;                cover changing the generated views/controllers and adding jqGrid for the list&lt;br /&gt;              page.&lt;br /&gt;          &lt;/div&gt;&lt;br /&gt;        &lt;br /&gt;          &lt;div&gt;&lt;b&gt;Resources&lt;/b&gt;&lt;/div&gt;Source: &lt;a href="http://sites.google.com/site/aoathout/myband-part2.zip"&gt;Grails Tutorial - Part 2&lt;/a&gt;&lt;br /&gt;&lt;div&gt;  &lt;span style=";font-size:small;color:red;"  &gt;** After downloading, rename the folder to "myband".&lt;/span&gt;&lt;br /&gt;Grails: &lt;a href="http://www.grails.org/"&gt;http://www.grails.org&lt;/a&gt;&lt;br /&gt;jQuery: &lt;a href="http://jquery.com/"&gt;http://jquery.com&lt;/a&gt;&lt;br /&gt;              jQuery UI: &lt;a href="http://jqueryui.com/"&gt;http://jqueryui.com&lt;/a&gt;&lt;br /&gt;              jqGrid: &lt;a href="http://www.trirand.com/blog"&gt;http://www.trirand.com/blog&lt;/a&gt;&lt;br /&gt;              fgMenu: &lt;a href="http://www.filamentgroup.com/lab/jquery_ipod_style_and_flyout_menus/"&gt;http://www.filamentgroup.com/lab/jquery_ipod_style_and_flyout_menus/&lt;/a&gt;&lt;br /&gt;              Formular: &lt;a href="http://wiki.github.com/fnagel/jQuery-Accessible-RIA/formular"&gt;http://wiki.github.com/fnagel/jQuery-Accessible-RIA/formular&lt;/a&gt;&lt;br /&gt;              Git: &lt;a href="http://git-scm.com/"&gt;http://git-scm.com&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;          &lt;/div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3498211330006616408-5261866319667790488?l=aoathout.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aoathout.blogspot.com/feeds/5261866319667790488/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://aoathout.blogspot.com/2010/06/grails-tutorial-part-2.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3498211330006616408/posts/default/5261866319667790488'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3498211330006616408/posts/default/5261866319667790488'/><link rel='alternate' type='text/html' href='http://aoathout.blogspot.com/2010/06/grails-tutorial-part-2.html' title='Grails Tutorial - Part 2'/><author><name>Aaron Oathout</name><uri>http://www.blogger.com/profile/17544558400157608670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3498211330006616408.post-3299123943764241170</id><published>2010-06-19T15:12:00.004-05:00</published><updated>2010-06-19T17:21:19.837-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='jquery'/><category scheme='http://www.blogger.com/atom/ns#' term='jqueryui'/><category scheme='http://www.blogger.com/atom/ns#' term='jqgrid'/><category scheme='http://www.blogger.com/atom/ns#' term='grails'/><title type='text'>Grails Tutorial - Part 1</title><content type='html'>I've spent a lot of time going through many blogs and tutorials on grails. Many of them are very good, but none of them seemed to address integrating Grails with jQuery components. Specifically jQuery UI/jqGrid/Formular components. So I decided I would put together a tutorial that would show how to integrate these great frameworks.&lt;br /&gt;&lt;br /&gt;The plan is to divide the tutorial into 4 or 5 parts. This part will cover creating the project and creating the domain layer. Other posts will cover the UI and Controller layers.&lt;br /&gt;&lt;br /&gt;The sample app for this tutorial will be a site for bands to keep track of the following:&lt;br /&gt;&lt;br /&gt;Band&lt;br /&gt;Member&lt;br /&gt;Instrument&lt;br /&gt;Song&lt;br /&gt;Set List&lt;br /&gt;Gig&lt;br /&gt;&lt;br /&gt;For this little project I will be using Git for source control, Grails 1.2.2, and all development is being done on a Mac.&lt;br /&gt;&lt;br /&gt;I like Git because it lets me have local repositories and if I'm work from a clone of a remote repository I can commit locally to track changes when I'm not connected to the net for some reason.&lt;br /&gt;&lt;br /&gt;&lt;font style="font-weight:bold;"&gt;Creating the project&lt;/font&gt;&lt;br /&gt;I'm not going to cover installing grails or git. If you don't have them installed and configured check out the &lt;a href="http://www.blogger.com/post-edit.g?blogID=3498211330006616408&amp;amp;postID=3299123943764241170#resources"&gt;Resources&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;There are a few things we need todo before we get into the actual code. Specifically we need to create out local git repo, create the grails project and commit the initial project structure to the repo.&lt;br /&gt;&lt;br /&gt;From a terminal type the following:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;cd ~/&lt;br /&gt;mkdir -p Repo/myband.git&lt;br /&gt;cd Repo/myband.git&lt;br /&gt;git --bare init&lt;br /&gt;&lt;br /&gt;cd ~/&lt;br /&gt;mkdir Projects&lt;br /&gt;cd Projects&lt;br /&gt;git clone ~/Repo/myband.git&lt;br /&gt;&lt;br /&gt;grails create-app myband&lt;br /&gt;cd myband&lt;br /&gt;&lt;br /&gt;git add .&lt;br /&gt;git commit -m "Initial Project Creation"&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;Ok, now that all of that is complete we can get down to business. Lets create the domain objects for the project.&lt;br /&gt;&lt;code&gt;&lt;br /&gt;grails create-domain-class Band&lt;br /&gt;grails create-domain-class Member&lt;br /&gt;grails create-domain-class Instrument&lt;br /&gt;grails create-domain-class Song&lt;br /&gt;grails create-domain-class SetList&lt;br /&gt;grails create-domain-class Gig&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Here is the code for the domain objects&lt;br /&gt; &lt;pre&gt;&lt;br /&gt;package myband&lt;br /&gt;class Band {&lt;br /&gt;&lt;br /&gt;    String name&lt;br /&gt;    Date dateCreated // grails will auto timestamp&lt;br /&gt;    Date lastUpdated // grails will auto timestamp&lt;br /&gt;&lt;br /&gt;    static hasMany = [members: Member, songs: Song, gigs: Gig]&lt;br /&gt;&lt;br /&gt;    static constraints = {&lt;br /&gt;        name(blank: false, unique: true)&lt;br /&gt;        dateCreated(display: false)&lt;br /&gt;        lastUpdated(display: false)&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    static mapping = {&lt;br /&gt;        members joinTable: [name: "BAND_MEMBER", column: "MEMBER_ID", key: "BAND_ID"]&lt;br /&gt;        songs joinTable: [name: "BAND_SONG", column: "SONG_ID", key: "BAND_ID"]&lt;br /&gt;        gigs joinTable: [name: "BAND_GIG", column: "GIG_ID", key: "BAND_ID"]&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    String toString() { name }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;package myband&lt;br /&gt;class Member {&lt;br /&gt;&lt;br /&gt;    String firstName&lt;br /&gt;    String lastName&lt;br /&gt;    String phoneNumber&lt;br /&gt;    Date dateCreated // grails will auto timestamp&lt;br /&gt;    Date lastUpdated // grails will auto timestamp&lt;br /&gt;&lt;br /&gt;    static hasMany = [instruments: Instrument]&lt;br /&gt;&lt;br /&gt;    static constraints = {&lt;br /&gt;        firstName(blank: false)&lt;br /&gt;        lastName(blank: false)&lt;br /&gt;        phoneNumber(blank: false, matches: "^\\(?(\\d{3})\\)?[- .]?(\\d{3})[- .]?(\\d{4})\$")&lt;br /&gt;        dateCreated(display: false)&lt;br /&gt;        lastUpdated(display: false)&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    static mapping = {&lt;br /&gt;        instruments joinTable: [name: "MEMBER_INSTRUMENT", column: "INSTRUMENT_ID", key: "MEMBER_ID"]&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    String toString() { "${firstName} ${lastName}" }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;package myband&lt;br /&gt;class Instrument {&lt;br /&gt;&lt;br /&gt;    String name&lt;br /&gt;    Date dateCreated // grails will auto timestamp&lt;br /&gt;    Date lastUpdated // grails will auto timestamp&lt;br /&gt;&lt;br /&gt;    static constraints = {&lt;br /&gt;        name(blank: false, unique: true)&lt;br /&gt;        dateCreated(display: false)&lt;br /&gt;        lastUpdated(display: false)&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    String toString() { name }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;package myband&lt;br /&gt;class Song {&lt;br /&gt;&lt;br /&gt;    String name&lt;br /&gt;    byte[] content&lt;br /&gt;    Date dateCreated // grails will auto timestamp&lt;br /&gt;    Date lastUpdated // grails will auto timestamp&lt;br /&gt;&lt;br /&gt;    static belongsTo = Band&lt;br /&gt;&lt;br /&gt;    static constraints = {&lt;br /&gt;        name(blank: false, unique: true)&lt;br /&gt;        content(nullable: true)&lt;br /&gt;        dateCreated(display: false)&lt;br /&gt;        lastUpdated(display: false)&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    String toString() { name }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;package myband&lt;br /&gt;class SetList {&lt;br /&gt;&lt;br /&gt;    String name&lt;br /&gt;    Date dateCreated // grails will auto timestamp&lt;br /&gt;    Date lastUpdated // grails will auto timestamp&lt;br /&gt;&lt;br /&gt;    static hasMany = [songs: Song]&lt;br /&gt;&lt;br /&gt;    static constraints = {&lt;br /&gt;        name(blank: false, unique: true)&lt;br /&gt;        dateCreated(display: false)&lt;br /&gt;        lastUpdated(display: false)&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    static mapping = {&lt;br /&gt;        songs joinTable: [name: "SET_LIST_SONG", column: "SONG_ID", key: "SET_LIST_ID"]&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    String toString() { name }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;package myband&lt;br /&gt;class Gig {&lt;br /&gt;&lt;br /&gt;    String venue&lt;br /&gt;    Date startTime&lt;br /&gt;    Date dateCreated // grails will auto timestamp&lt;br /&gt;    Date lastUpdated // grails will auto timestamp&lt;br /&gt;&lt;br /&gt;    static hasMany = [setLists: SetList]&lt;br /&gt;    static belongsTo = Band&lt;br /&gt;&lt;br /&gt;    static constraints = {&lt;br /&gt;        venue(blank: false)&lt;br /&gt;        startTime(nullable: false, attributes: [precision: 'minutes'])&lt;br /&gt;        dateCreated(display: false)&lt;br /&gt;        lastUpdated(display: false)&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    static mapping = {&lt;br /&gt;        setLists joinTable: [name: "GIG_SET_LIST", column: "SET_LIST_ID", key: "GIG_ID"]&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    String toString() { "${venue} - ${startTime.format('MM/dd/yyyy h:m a')}"}&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now lets get the controller / view creation out of the way since we have defined our domain objects. &lt;br /&gt;&lt;code&gt;&lt;br /&gt;grails generate-all myband.Band&lt;br /&gt;grails generate-all myband.Member&lt;br /&gt;grails generate-all myband.Instrument&lt;br /&gt;grails generate-all myband.Song&lt;br /&gt;grails generate-all myband.SetList&lt;br /&gt;grails generate-all myband.Gig&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;The last piece is to add some data to the BootStrap.groovy file so we have some data to work with.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;import grails.util.Environment&lt;br /&gt;import myband.Band&lt;br /&gt;import myband.Member&lt;br /&gt;import myband.Instrument&lt;br /&gt;import myband.Song&lt;br /&gt;import myband.SetList&lt;br /&gt;import myband.Gig&lt;br /&gt;&lt;br /&gt;class BootStrap {&lt;br /&gt;&lt;br /&gt;     def init = { servletContext -&gt;&lt;br /&gt;         // Only want to insert for dev testing&lt;br /&gt;         if (Environment.isDevelopmentMode()) {&lt;br /&gt;             def acousticGuitar = new Instrument(name: "Acoustic Guitar").save()&lt;br /&gt;             def electricGuitar = new Instrument(name: "Electric Guitar").save()&lt;br /&gt;             def drums = new Instrument(name: "Drums").save()&lt;br /&gt;             def piano = new Instrument(name: "Piano").save()&lt;br /&gt;&lt;br /&gt;             def singer = new Member(firstName: "Joe",&lt;br /&gt;                                     lastName: "Singer",&lt;br /&gt;                                     phoneNumber: "515.595.1234",&lt;br /&gt;                                     instruments: [electricGuitar]).save()&lt;br /&gt;&lt;br /&gt;             def guitarist = new Member(firstName: "Tim",&lt;br /&gt;                                        lastName: "Guitarist",&lt;br /&gt;                                        phoneNumber: "515.595.1235",&lt;br /&gt;                                        instruments: [acousticGuitar, piano]).save()&lt;br /&gt;&lt;br /&gt;             def drummer = new Member(firstName: "Adam",&lt;br /&gt;                                      lastName: "Drummer",&lt;br /&gt;                                      phoneNumber: "515.595.1236",&lt;br /&gt;                                      instruments: [drums]).save()&lt;br /&gt;&lt;br /&gt;             def song1 = new Song(name: "Long Lost").save()&lt;br /&gt;             def song2 = new Song(name: "No Home").save()&lt;br /&gt;&lt;br /&gt;             def gig1 = new Gig(venue: "Valair Ballroom", startTime: new Date()).save()&lt;br /&gt;&lt;br /&gt;             def myBand = new Band(name: "My Band",&lt;br /&gt;                                   members: [singer, guitarist, drummer],&lt;br /&gt;                                   songs: [song1, song2],&lt;br /&gt;                                   gigs: [gig1]).save()&lt;br /&gt;&lt;br /&gt;         }&lt;br /&gt;     }&lt;br /&gt;     def destroy = {&lt;br /&gt;     }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ok, not to bad. We created a few domain classes, defined some relationships and changed the database mappings for our join tables. Now we can type "grails run-app" from the terminal to start things up. &lt;br /&gt;&lt;br /&gt;Once the app has been started grails will give you the URL for the site (&lt;code&gt;http://localhost:8080/myband&lt;/code&gt;). This presents us with the default index page that lists our controllers that were generated. Click through the controllers to pull up the generated views (list/edit/create/show).&lt;br /&gt;&lt;br /&gt;Now we just need to commit our changes to our git repo:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;cd ~/Projects/myband&lt;br /&gt;git commit -a -m "Domain and Controllers created"&lt;br /&gt;git push origin master&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;That's probably enough for this first post. The next post will cover changing the views and main layout. We will also integrate jQuery-UI theme css into our layout so we can use the themeswitcher tool.&lt;br /&gt;&lt;br /&gt;&lt;div id="resources" style="white-space:nowrap;"&gt;&lt;br /&gt;&lt;font style="font-weight:bold;"&gt;Resources&lt;/font&gt;&lt;br /&gt;     Source: &lt;a href="http://sites.google.com/site/aoathout/myband-part1.zip"&gt;Grails Tutorial - Part 1&lt;/a&gt;&lt;br /&gt;           ** After downloading, rename the folder to "myband".&lt;br /&gt;     Grails: &lt;a href="http://www.grails.org/"&gt;http://www.grails.org&lt;/a&gt;&lt;br /&gt;     jQuery: &lt;a href="http://jquery.com/"&gt;http://jquery.com&lt;/a&gt;&lt;br /&gt;     jQuery UI: &lt;a href="http://jqueryui.com/"&gt;http://jqueryui.com&lt;/a&gt;&lt;br /&gt;     jqGrid: &lt;a href="http://www.trirand.com/blog"&gt;http://www.trirand.com/blog&lt;/a&gt;&lt;br /&gt;     Formular: &lt;a href="http://wiki.github.com/fnagel/jQuery-Accessible-RIA/formular"&gt;http://wiki.github.com/fnagel/jQuery-Accessible-RIA/formular&lt;/a&gt;&lt;br /&gt;     Git: &lt;a href="http://git-scm.com/"&gt;http://git-scm.com&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3498211330006616408-3299123943764241170?l=aoathout.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aoathout.blogspot.com/feeds/3299123943764241170/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://aoathout.blogspot.com/2010/06/grails-tutorial-part-1.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3498211330006616408/posts/default/3299123943764241170'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3498211330006616408/posts/default/3299123943764241170'/><link rel='alternate' type='text/html' href='http://aoathout.blogspot.com/2010/06/grails-tutorial-part-1.html' title='Grails Tutorial - Part 1'/><author><name>Aaron Oathout</name><uri>http://www.blogger.com/profile/17544558400157608670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3498211330006616408.post-5542175292228203321</id><published>2010-06-13T00:38:00.000-05:00</published><updated>2010-06-13T00:41:09.365-05:00</updated><title type='text'>Grails jquery-ui plugin</title><content type='html'>I have started a grails plugin for the jquery-ui widgets. &lt;br /&gt;&lt;br /&gt;The goal of this project is to provide grails taglibs for the jquery-ui library. While the jquery-ui api has decent documentation and isn't hard to learn / use, it would be nice to have some tags that make things very simple (and can eventually be used in scaffolding). Also I think it would be good to have a working demo of using these widgets in a grails application.&lt;br /&gt;&lt;br /&gt;The project &lt;a href="http://github.com/aoathout/grails-jquery-ui/"&gt;source&lt;/a&gt; can be found on github.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3498211330006616408-5542175292228203321?l=aoathout.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aoathout.blogspot.com/feeds/5542175292228203321/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://aoathout.blogspot.com/2010/06/grails-jquery-ui-plugin.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3498211330006616408/posts/default/5542175292228203321'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3498211330006616408/posts/default/5542175292228203321'/><link rel='alternate' type='text/html' href='http://aoathout.blogspot.com/2010/06/grails-jquery-ui-plugin.html' title='Grails jquery-ui plugin'/><author><name>Aaron Oathout</name><uri>http://www.blogger.com/profile/17544558400157608670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3498211330006616408.post-4805536039128249803</id><published>2010-06-12T22:29:00.000-05:00</published><updated>2010-06-12T22:40:38.415-05:00</updated><title type='text'>Grails jqGrid Plugin</title><content type='html'>I have started a grails plugin for the wonderful jquery jqgrid component. &lt;br /&gt;&lt;br /&gt;The goal of this project is to provide grails taglibs for the jqgrid library. While the jqgrid library api has very good documentation and isn't hard to learn / use, it would be nice to have some tags that make things very simple (and can eventually be used in scaffolding).&lt;br /&gt;&lt;br /&gt;The project &lt;a href="http://github.com/aoathout/grails-jqgrid/"&gt;source&lt;/a&gt; can be found on github.&lt;br /&gt;&lt;br /&gt;If you haven't seen &lt;a href="http://www.trirand.com/blog/"&gt;jqgrid&lt;/a&gt;, check it out.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3498211330006616408-4805536039128249803?l=aoathout.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aoathout.blogspot.com/feeds/4805536039128249803/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://aoathout.blogspot.com/2010/06/grails-jqgrid-plugin.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3498211330006616408/posts/default/4805536039128249803'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3498211330006616408/posts/default/4805536039128249803'/><link rel='alternate' type='text/html' href='http://aoathout.blogspot.com/2010/06/grails-jqgrid-plugin.html' title='Grails jqGrid Plugin'/><author><name>Aaron Oathout</name><uri>http://www.blogger.com/profile/17544558400157608670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
