Archive

Archive for April, 2011

a perfect team: Grails Taggable plugin and JQuery Tagit

April 8th, 2011 9 comments

In a recent Grails project the customer asked for support of a tagging functionality for some domain classes. In order not to clutter the tagspace too much auto-complete should be available when editing the tags.

In fact there is a very simple and elegant solution for this. On the application’s side, there’s the Grails Taggable plugin available. For the frontend side JQuery has a nice plugin called  Tagit plugin caring about editing tags and auto-completion. Both play together very well – showing this is the intention of this post.

Setting up the ‘to-be-tagged’ domain class

After installing the taggable plugin the usual way using

grails install-plugin taggable

setting up the ‘to-be-tagged’ domain classes is fairly trivial, the only thing left is to add ‘implements Taggable’ to the ‘to-be-tagged’ domain classes, e.g.

import org.grails.taggable.Taggable
class Product implements Taggable {
    String name
    double price
}

By marking the domain class with the taggable interface it gets injected some methods for manipulating its tags on instance level

  • addTag,
  • addTags,
  • getTags,
  • parseTags,
  • removeTag,
  • setTags

as well as some new methods on class level:

  • getAllTags,
  • getTotalTags,
  • countByTag.

Setting up JQuery Tagit in the Grails application

Since the Tagit plugin depends on JQueryUI for autocompletion, lets first install this in the application. Using the resources plugin for managing our css/js/image resources is also a good idea:

grails install-plugin jquery-ui
grails install-plugin resources

Download an unzip the latest version of tagit (1.5 when authoring this post) to some temporary location. We basically need to copy three files contained in the zip:

  • tagit/js/tagit.js to <grailsapp>/web-app/js
  • one of tagit/css/tagit-<yourchoice>.css and tagit/css/ui-anim_basic_16x16.gif to <grailsapp>/web-app/css

Since we’ve added resources to our project let’s declare them as a module for the resources plugin. For more information on this concept, checkout the docs of the Grails resources plugin.

modules = {
 'tagit' {
 dependsOn 'jquery-ui'
 resource 'css/tagit-gradient-blue.css'
 resource 'js/jquery/tagit.js'
 }
}

Editing the view

Next thing is the frontend. To get started, let’s generate a controller and views for the given domain class:

grails generate-all Product

For simplicity, we’ll only care about the edit view for the rest of this post. The code of the generated view is the starting point. First we need to make use of the declared resources and second we need to render the already existing tags and apply the tagit plugin.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
<%-- in the head section --%>
<r:use modules="tagit"/>
...
<%-- in the form section --%>
<fieldset class="form">
  <r:script>
    $(function() {
      $("ul[name='tags']").tagit({select:true, tagSource: "${g.createLink(action: 'tags')}"});
    });
  </r:script>
 
  <h3>Tags</h3>
  <div class="fieldcontain">
    <ul name="tags">
      <g:each in="${productInstance.tags}">
        <li>${it}</li>
      </g:each>
    </ul>
  </div>
</fieldset>

L.3 adds the js/css resources. L.9 is requires some explanation, we’re decorating the ul tag having an attribute name='tags' with the tagit widget. The parameter select=true is crucial since it passes back the chosen tags upon form submission as a multivalued select-box. Specifying a tagSource URL provides auto-completion. In l.15-19 we’re displaying the existing tags in a simple unordered list. N.B. the name attribute mirrors the name of the select-box being created.

Editing the controller

The ProductController must be modified to store given tags upon form submission and to provide auto-completion. For storing tags, the update action requires a single line change:

69
70
productInstance.properties = params
productInstance.tags = params.tags // new line to be inserted

tags isn’t a real property it is not covered by l.69 and an explicit call to setTags() is necessary.

For auto-completion a new action tags is introduced:

def tags = {
  render Tag.findAllByNameIlike("${params.term}%")*.name as JSON
}

JQuery-UI auto-completion passes the partially entered tag in request parameter term. The code above searches for all tags starting with the given term and returns their name as JSON.

Result & Conclusion

With these very few lines of code a comfortable user interface for tagging with auto-completion could be established. Kudos to the authors of the JQuery Tagit and Grails Taggable plugins. These two plugins are a perfect match.

Categories: Uncategorized Tags: ,