Saturday, 3 August 2013

Grails with jQuery UI autocomplete

In my first post I'll show you how to create a simple application in Grails that uses jQuery UI autocomplete and AJAX.

  1. Project setup
  2. Building Application:
    • creating domain class
    • creating controller
    • adding data via Bootstrap.groovy
    • creating view
    • modifying resource configuration
    • creating javascript file

Project setup


  • Create a new project - I called it GrailsAutocomplete
  • Go to grails-app/conf/BuildConfig.groovy and in the plugins section paste jQuery UI dependency:
    compile ":jquery-ui:1.8.24"  

Building Application


Creating domain class

  • create com.example.Country domain class
    package com.example

    class Country {
   
        String name

        static constraints = {
            name(blank: false, unique: true)
        }
    }



Creating controller

  • create com.example.Country controller
       package com.example

      import grails.converters.JSON

      class CountryController {
   
           def scaffold = true
   
           def index() {
                 redirect action: "autocomplete", params: params       
           }
   
          def autocomplete() {
                 params.max = Math.min(params.max ? params.int('max') : 10, 100)
                 [countryInstanceList: Country.list(params), countryInstanceTotal: Country.count()]
          }
   
         def getAllCountries() {
               def countries = Country.list()
               def response = []
       
            countries.each {
                  response << "${it.name}"
           }
            render response as JSON
        }
  }

  • the index() method will redirect us to the autocomplete method
  • the autocomplete() method will get all the country instance saved in the DB and pass them as a list
  • by convention Grails will match the name of a method to a view with the same name; in a bit we will create our views/country/autocomplete.gsp
  • the getAllCountries() method retrieves a list of all countries from DB
  • we use each closure to populate the response list with the names of each Country instance
  • our return value is the response rendered as JSON
  • of course we don't have any country stored in the DB
Adding dummy data

  • conf/BootStrap.groovy is a good place where we can add some countries to our DB
import com.example.Country

class BootStrap {

    def init = { servletContext ->
        def poland = new Country(name: "Poland");
        poland.save(failOnError: true);
       
        def holland = new Country(name: "Holland");
        holland.save(failOnError: true);
       
        def uk = new Country(name: "United Kingdom");
        uk.save(failOnError: true);
       
        def uae = new Country(name: "United Arab Emirates");
        uae.save(failOnError: true);
       
        def honduras = new Country(name: "Honduras");
        honduras.save(failOnError: true);
       
       
    }
    def destroy = {
    }
}
Creating view

  • we can create now our views/country/autocomplete.gsp
<%@ page import="com.example.Country" %>
<!doctype html>
<html>
        <head>
                <meta name="layout" content="main">
                <g:set var="entityName" value="${message(code: 'country.label', default: 'Country')}" />
                <title><g:message code="default.list.label" args="[entityName]" /></title>
                 <r:require module="jquery-ui"/>
                <g:javascript library="util"/>
        </head>
        <body>
                <a href="#list-country" class="skip" tabindex="-1"><g:message code="default.link.skip.label" default="Skip to content&hellip;"/></a>
                <div class="nav" role="navigation">
                        <ul>
                                <li><a class="home" href="${createLink(uri: '/')}"><g:message code="default.home.label"/></a></li>
                                <li><g:link class="create" action="create"><g:message code="default.new.label" args="[entityName]" /></g:link></li>
                        </ul>
                </div>
                <div id="list-country" class="content scaffold-list" role="main">

            <div>
                <h1 style="float: left;"><g:message code="default.list.label" args="[entityName]" /></h1><br/>
                <input style="float: right; margin: 0px 10px 10px 0px;" type="text" name="country" id="country_textField" value="" placeholder="Enter country..."/>
            </div>

                        <g:if test="${flash.message}">
                        <div class="message" role="status">${flash.message}</div>
                        </g:if>
                        <table>
                                <thead>
                                        <tr>
                                       
                                                <g:sortableColumn property="name" title="${message(code: 'country.name.label', default: 'Name')}" />
                                       
                                        </tr>
                                </thead>
                                <tbody>
                                <g:each in="${countryInstanceList}" status="i" var="countryInstance">
                                        <tr class="${(i % 2) == 0 ? 'even' : 'odd'}">
                                       
                                                <td><g:link action="show" id="${countryInstance.id}">${fieldValue(bean: countryInstance, field: "name")}</g:link></td>
                                       
                                        </tr>
                                </g:each>
                                </tbody>
                        </table>
                        <div class="pagination">
                                <g:paginate total="${countryInstanceTotal}" />
                        </div>
                </div>
        </body>
</html>

  • inside the head tag we have two important lines:
               <r:require module="jquery-ui"/>
                <g:javascript library="util"/>

  • r:require uses Grails resource plugin that will allow us to use jQuery UI on this page
  • g:javascript will import JS file called util
  • we have to tell Grails where to look for this file
  • Modifying resource configuration
  • go to conf/ApplicationResource.groovy and add reference to util resource
  •  modules = {
        application {
            resource url:'js/application.js'
        }
        util {
            resource url:'js/util.js'
        }
    }
  • Creating javascript file
  • now we can create a util.js file in  web-app/js folder
$(document).ready(function() {
    $.ajax({
        type: "GET",
        url: "/GrailsAutocomplete/country/getAllCountries",
        success : function(response) {

            $("#country_textField").autocomplete({
                source: response
            });
        }
    });

});
  • we do an AJAX request to /GrailsAutocomplete/country/getAllCountries once we finish loading the html for the page
  • this URL will map to our Country controller and to it's method getAllCountries() that returns a JSON file with the names of the countries that are stored in the DB
  • we use this JSON to populate our autocomplete
  • note that the $(#country_textField) matches the id of our input from autocomplete.gsp
Running the app
Now we can run our app and go to:
http://localhost:8080/GrailsAutocomplete/country/
  • we should see a list of countries and an input box on the right-hand side
  • when you start typing 'ola' the list should be populated with 'Holand' and 'Poland'

3 comments:

  1. Thank you! your code is very helpful and easy to understand..

    ReplyDelete
  2. take a look at this autocomplete, it's awesome, http://justwebcode.blogspot.com/2017/07/autocomplete-textbox-with-jquery.html

    ReplyDelete
  3. Thank you! your code is very helpful.

    ReplyDelete