End-users are expecting more from their web applications and, fortunately, tools for making this
happen without a Herculean effort are appearing on the scene and earning traction very quickly.
This project incorporates several of these technologies:
- Backbone: A javascript library that offers a model-view-controller approach to delivering greater client-side interactivity
- Underscore: A templating and general purpose library for javascript
- CoffeeScript: A language that compiles into javascript. It offers lint-like checking in the compile phase and encourages more elegant and easy to read code.
- HAML: Haml takes your gross, ugly templates and replaces them with veritable Haiku.
You’ll need the following skills.
- Basic 101-Level Grails: This shouldn’t be your first Grails app, but we’re not getting too crazy.
- Intermediate Javascript: You should “get” javascript, but you don’t have to be an expert.
- Basic JQuery: You should “get” selectors.
- Read up on CoffeeScript, Backbone, Underscore and HAML: shouldn’t take more than an hour or two.
- Some experience with JSON
This is no genius application. It’s got one working domain class and one controller. The UI consists of
one page that defers most of the work to a component that is built using CoffeeScript, Backbone and Underscore.
Barista is the domain class that represents a fictional coffee shop’s Baristas. Once you’ve built the App,
select the BaristaController. The default will list the Baristas as a list with a text entry field below. You
can add new Baristas by typing into this field and you can delete Baristas by selecting the delete button that
appears dynamically beside each Barista as you mouse over the entries.
TODO: Extend this application to show how to implement master-detail relationships and browser history.
Grab the app via Git:
git clone git@github.com:leopoldodonnell/Coffee-With-Backbone.git
Compile and run the app
cd Coffee-With-Backbone
grails compile
grails run-app
Important CoffeeScript Note:
When you’re working with CoffeeScript files, you must compile them, they are not auto-compiled while
your application is running (maybe it will be fixed in a future version of the coffee-script plugin).
Fortunately, the generated javascript will be picked up by your already running application, so you
won’t have to kill your app and restart with each script update.
The compile is simple:
grails compile
Start with the configuration. Here’s where you need to make sure that the resource plugin will see your
sources and load the javascript libraries you’ll need.
Plugins
Take a look in the application.properties file. The coffeescript plugin, us all you’ll need in the future,
but this app is also include jquery-ui. You may also want to consider using a few other plugins for your
production-ready application.
You may also consider:
- yui-minify-resources – to minify your generated javascript in production
- zipped-resources – to zip your generated javascript in production
- cache-headers – improve client-side caching.
Configuration
In grails-app/conf/Config.groovy…
grails.resources.adhoc.patterns = ['/images/*', '/css/*', '/js/*', '/plugins/*', '/js/coffeescriptGenerated/*']
In grails-app/conf/ApplicationResources.groovy you’ll add the following module…
backbone { dependsOn 'jquery'
resource url:'/js/underscore.js', disposition:'head' resource url:'/js/backbone.js', disposition:'head' }
HAML
Next checkout the HAML layout: grails-app/views/layouts/main.haml. Notice how much more readable it is now that all of HTML cruft has been eradicated (note to developers – watch your indentation, its important in HAML). We’ve added two modules, backbone and jquery-ui. The jquery-ui is used to illustrate how you might integrate it into
your CoffeeScript-ized Backbone code.
GRAILS SOURCES
Take a quick look at the domain model: grails-app/domain/cwb/Barista.groovy. Nothing much there, but enough to
illustrate our solution.
The next item, grails-app/contollers/cwb/BaristaController.groovy, is more involved. This a RESTFULL controller
that is setup to serve both HTML and JSON responses. Note the imports for the converters and the use of
withFormat for several of the actions. Sadly, withFormat will not work for all of the RESTFUL
actions.
In the cases of Save, Update and Delete, it is necessary to check the request format or the accept
header element (in the case of Delete). Here’s a snippet…
def update() { Barista barista = Barista.get(params.id)
if (request.format == 'json') { ...
and
def delete() { Barista barista = Barista.get(params?.id)
// The only way, it seems, to know if the delete is an Ajax Delete boolean isJson = request.getHeader('accept') =~ /application\/json/
if (isJson) { ...
THE UI
Now take a quick look at the view for the default action, list: grails-app/views/barista/list.haml. Once
again, note how clean it looks!
In the header, we setup the JSON data to populate the Barista list and then later in the body, we load our
Bacbone-ized component, src/coffee/coffee_with_backbone.coffee and our page specific CoffeeScript code
src/coffee/barista.coffee.
I hope these files help you on your way to adding these technologies to your own project and have you
building faster and slicker client-side applications!
Enjoy,
Leo O’Donnell