Aug
11
2006

Grails + Yahoo Autocomplete = Giddy Up

My little grails SMS gateway is powering along. I’ve now integrated Yahoo autocomplete into my "New SMS" page and it works just great. Now my users can begin typing entries from their addressbook, and get that snazzy dropdown happening as they type. Even works with multiple elements when you type in a comma. Sample below:

Autocomplete in CyaThen.com

I’ve been really impressed with how customisable Yahoo have made it. You can wire up the datasource to be Ajax (which is the way I went since Grails makes the xml generation so easy), or an in-page array. You can apply all kinda fades and delays and caching and… well, check out their example page to see all the customise options.

Thought it might be useful to other grails guys to jot down the steps I needed to go through to get it happening. This only applied to Grails 0.2, the file might be already included in a future version.

1. You need to download the Yahoo components from sourceforge since Grails 0.2 didn’t include the autocomplete_min.js file that you need. Track down that file and copy it into the /web-app/js/yahoo directory in your grails app.

2. Edit the JavaScript TagLib.groovy and make sure the yahoo map is edited to include ‘yahoo/autocomplete-min’  (note their is no .js on the end of that one)

3. Inside the view that you want to have an autocomplete field, edit your html <head> element to include <g:javascript library="yahoo" /> which will pull in all the Javascript you need.

4. Add a script element that will tell wire up your input element to your backend XML datasource. Here’s what mine looks like:

<script>
    var myDataSource = new YAHOO.widget.DS_XHR("search", ["person", "name"]);
    myDataSource.responseType = myDataSource.TYPE_XML;
    var myAutoComp = new YAHOO.widget.AutoComplete('numbers','customcontainer', myDataSource);
    myAutoComp.delimChar = ","
</script>

This piece of magic tells the yahoo component to call my "search" action, and expect the returned XML to have an array of "person" elements, each with a "name" field to display. The autocomplete line wires up that datasource to my "numbers" input box using the empty "customcontainer" DIV to display the funky slidy autocomplete list.

5. Finally, you just need to create a Grails on your current controller to create the XML. You’ll get the user’s query is params.query and you need to return some well formed XML that the autocomplete can parse. With a builder that couldn’t be easier.

def search = {

  def str = params.query?.toUpperCase()
  println "Searching for $str";
  // do your custom stuff here
  render(contentType: "text/xml") {
    addressbook() {
        for (c in acc.contacts) {
            if (c.fullName().toUpperCase() =~ /${str}/ || c.mobile =~ /${str}/) {
                person() {
	    	    name(c.fullName() + " (" + c.mobile + ")")
	    	}
    	    }
    	 }
    }
  }
}

If I could work out a better way to make the regexps case insenitive that’d look a lot smoother… but you get the idea. Yahoo gives you some sample CSS which is the look and feel I’m using above, but you can customise with your own CSS class/id/whatever if you have the inclination. Very tunable.

Anyways, I give autocomplete the big tick. Huge props to the Yahoo guys for opening up this stuff. Loving every second of it.

About the Author: Glen Smith

8 Comments + Add Comment

  • I read some of your Grails posts. And it seems to be a really good showcase.

    What are your plans with it? Will it be downloadable as reference for the community. I’m really interested in taking a look how you did some things. I’m starting myself with Grails currently.

     

     

  • You can have case insensitive regexes by starting them with
     (?i)
    e.g.
     /(?i)myPatternString/

  • Thanks mate! That’s awesome. I figured there had to be a way to do case insensitive matching without creating a custom Matcher object.

  • Good question. The SMS gateway bit has actually been a request from a few separate clients, so I’ll probably put up a site that I charge them a token amount to cover my SMS costs.

    Which is not to say that I might not opensource the thing if its interesting to people. I have another Grails project that I’m earmarking for that purpose, too. But more details on that when I’ve got something to show and tell.

  • i have created the xml file but second node value from the xml file is not reading its only reading the first value on any key down my sample xml file
    <result>
    <car>FORD KA 1.3i Zetec [70] 3dr Hatchback Petrol Manual</car>
    <car>FORD KA 1.3i luxuryKa [70] 3dr Hatchback Petrol Manual</car>
    <car>…</car>
    </result>

  • now it working thanks

    i have passed the xml like

    <resultset><result>
    <car>bmw</car></result><result>
    <car>skoda</car></result></resultset>

  • now it working thanks

    i have passed the xml like

    <resultset><result>
    <car>bmw</car></result><result>
    <car>skoda</car></result></resultset>

  • Just to help those who want to try with the last version of YUI (2.2.0a for now), 2 things to do :

    1. the line
      myXHRDataSource.responseType = myXHRDataSource.TYPE_XML;

      should be changed to

      myXHRDataSource.responseType = YAHOO.widget.DS_XHR.TYPE_XML;
    2. change the line
      <g:javascript library="yahoo" />

      to

              <script type="text/javascript"
      src="${createLinkTo(dir:'js/yahoo/build/yahoo-dom-event',
      file:'yahoo-dom-event.js')}"></script>
              <script type="text/javascript"
      src="${createLinkTo(dir:'js/yahoo/build/connection',
      file:'connection-min.js')}"></script>
              <script type="text/javascript"
      src="${createLinkTo(dir:'js/yahoo/build/autocomplete',
      file:'autocomplete-debug.js')}"></script>
      

      after having move the YUI files to the right directory.

    Hope this could help.

Leave a comment

Glen Smith

About Glen

Co-author Grails in Action