CHAPTER 8

Web 2.0—Ajax and Friends

So far in this book, we have relied on a few basic items to create our site, and, as of right now, it is fully functioning. Users have the ability to log in, create to-dos, create buddies, and so on. And while these make for a good application, good applications will not generate revenue. The Web is filled with many bad applications, quite a few good ones, and far and few between excellent ones. In this and the following two chapters, we will try to add some excellence to our web application by applying some Web 2.0 techniques.

What do we mean by excellence? Some developers try to cram every Ajax component and every Web 2.0 concept under the sun into their applications. Many times, this approach can fail. You end up overcomplicating the page and making it difficult to use. In this chapter's examples, we will try to toe the line between enhancing the page and making it unmanageable. Each component we will add will supply functionality that the users should be able to enjoy.

We will start it off slowly with some basic plug-ins that add some Web 2.0 functionality. From there, we will add a mail service, which we will use in this chapter and in Chapter 10, which covers reporting. After that, we will dive into some good old-fashioned Ajax and demonstrate the flexibility of Ajax in Grails. We will finish up with an RSS feed, which can be useful if you want to have your to-dos displayed on an RSS reader like iGoogle.

Advanced Presentation Components

Currently, our sample application's to-do page is pretty basic, as shown in Figure 8-1. We can improve the application by adding functionality here.

image

Figure 8-1. The current to-do page in Collab-Todo

We will focus on three areas that will make this page more useful to users:

  • Allow for the use of rich text in the to-do notes.
  • Make the to-dos searchable.
  • Allow for uploading a file associated with a to-do.

To add these features, we will make use of an ever-growing list of plug-ins for Grails.

Adding Rich-Text Capabilities

Currently, to-do note entry is very limited. You cannot style text (such as italics or boldface) or format it (say, into a bulleted list). We have a few ways to address this need:

HTML: Allow users to insert their own HTML code, but that would be a bad idea. Not only would it require users to know how to do this, but if they made a mistake, it could throw off the entire layout of the page by not closing the HTML tags.

Text editor: Add a rich text editor. This type of editor can provide near Microsoft Word–type functionality to a web site. Not only can you allow rich text, but you can also let the users upload images, Flash movies, and even files to your web application. The FCK editor plug-in1 is a good example of this sort of editor. Figure 8-2 shows an example of the FCK editor embedded into an application. Although this is, as Borat would say, "very nice," it is a bit of overkill for our needs. Not only that, it might break some of the smooth lines of our page.

image

Figure 8-2. The FCK editor plug-in in action

__________

Wiki markup: Systems like Wikipedia and even regular homegrown content management systems (CMS) are turning to using a markup language for their rich content. This allows a generally more simplified system of displaying and formatting text. You can add styles like bold and italicized text, as well as formatting like bulleted and numbered lists. You can even use more advanced formatting for code display, such as a dashed border with a header. Using wiki markup is becoming a popular solution for web sites, and this is the approach we'll take with our application.


Note A downside to wikis is that there is no set standard. So every wiki will implement the items differently. Some wikis can be very similar, while others will differ greatly.


While there are many wiki markup solutions, we are going to use Radeox, because Grails has a plug-in wrapper for it.2 The Radeox plug-in uses SnipSnap as its wiki engine.

As with other Grails plug-ins, you can install the Radeox plug-in by downloading from its site at http://www.grails.org/Radeox+plugin or by using this command:

> grails install-plugin radeox


Note At the time of this writing, the plug-in required one tweak to make it work: add a getName() method to the GroovyMacro.groovy file in the plug-in.


Let's start by adjusting our Bootstrap.groovy file to bold the word task in our notes. To do this, we surround the word we want to bold with double underscores (__), as shown in Listing 8-1.3

Listing 8-1. A Note Format Adjustment in Bootstrap.groovy

todo =
  new Todo(owner: user1, category: cat1, name: 'Our First Task',
           createDate: new Date(), startDate: new Date(), priority: '1',
           status: '1', dueDate: new Date() + 7, lastModifiedDate: new Date(),
           note: 'A note about our __task__.').save()

__________

3. See http://snipsnap.org/space/snipsnap-help for SnipSnap text-formatting markup guidance.

If you now view the page, you won't see the formatting added to the sentence. In order to have Radeox format the text, you need to update the note section of the to-do page and surround it with the <g:radeoxRender> tag, as shown in Listing 8-2.

Listing 8-2. The _detail.gsp Page Note Section Updated with the Radeox Tag

<g:radeoxRender>${todo?.note}</g:radeoxRender>

Now when the page is rendered, you will see the note with task, as shown in Figure 8-3.

image

Figure 8-3. The to-do page with the Radeox plug-in in use

Adding Search Capabilities

Currently, the only way to search for a particular task is to literally open up every task and see what is in there. While this may work if you have a small number of tasks, it will quickly become cumbersome as the application grows—especially if the keyword you are looking for is buried in the notes.

As in previous chapters, we are not only going to make use of a plug-in, but a plug-in that is based on tried-and-true Java technologies. The Searchable plug-in is based on the OpenSymphony Compass Search Engine framework,4 which in turn uses Apache Lucene under the covers.

The Searchable plug-in is supplied with Grails. Install it by issuing the following command:

> grails install-plugin searchable


Note At the time of this writing, the Searchable plug-in had a mapping issue. To get it to work, you may need to copy the directory plugins/searchable-0.4.1/grails-app/views/searchable to your main grails-app/views directory. This will allow the search views to be local.


The Searchable plug-is a snap to set up and use. The plug-in allows you to decide which domain objects should be searchable. We want to make the to-dos searchable, so we add the line static searchable = true to our Todo domain object, as shown in Listing 8-3.

Listing 8-3. Marking Our Todo As Searchable in domain/Todo.groovy

class Todo {

    static searchable = true
    // . . . continued . . .
}

And that is really all we need to do. So what does that give us?

If you go to http://localhost:8080/collab-todo/searchable, you will see the default searchable page. You can type in a word to search for and get the results. Figure 8-4 shows the results of searching for task.

__________

image

Figure 8-4. The results of searching for the word "task"

You will notice that some of our items do not show up well. This is because these items were formatted with wiki markup to be used with our Radeox plug-in. This really is not acceptable, so let's take care of that now. To fix this, we need to modify the search view directly. We just need to change one line in grails-app/searchable/index.gsp—line 142, as shown Listing 8-4 (which is a partial listing of the file with the modified line bolded).

Listing 8-4. Adding the Radeox Call to the Searchable Page (views/searchable/index.gsp)

<div class="result">
    <g:set var="className" value="${ClassUtils.getShortName(result.getClass())}" />
    <g:set var="link" value=
       "${createLink(controller: className[0].toLowerCase() + className[1..-1],
        action: 'show', id: result.id)}" />
    <div class="name"><a href="${link}">${className} #${result.id}</a></div>
    <g:set var="desc" value="${result.toString()}" />
    <g:if test="${desc.size() > 120}">
        <g:set var="desc" value="${desc[0..120] + '...'}" />
    </g:if>
    <div class="desc">
        <g:radeoxRender>${desc.encodeAsHTML()}</g:radeoxRender>
    </div>
    <div class="displayLink">${link}</div>
</div>

All that we had to do was wrap the response with the Radeox renderer. As shown in Figure 8-5, the response will now be formatted properly.

image

Figure 8-5. The Grails Searchable plug-in with the Radeox formatting

Allowing File Uploads

Some web applications allow users to upload files. For our application, we'll add the ability to upload a file for each of the to-dos, and then retrieve (download) that file later. The uploaded files can be stored either on the application server or the database itself. For our example, we are going to store the file in the database, mainly due to ease of doing so and because we're working with only one file, so space is not an issue.

Uploading the File

Grails will use Spring's file upload capability to help upload the file. Uploading a file is a fairly simple process, requiring the following steps:

  • Review necessary properties on the Todo domain.
  • Add a link to upload it in our list page.
  • Add configurations to the Spring resources.xml file.
  • Create the necessary code in our controller to store and retrieve the file.

In order to store the data, all you are required to have is a byte[] for data. But when you return the data, the end user probably wants to have the original name of the file. In addition, being specific about the type of data returned will help the browser know how to process the data. For example, if it's a PDF, the browser will automatically know to open it as a PDF. To handle this, in Chapter5, we added the variable associatedFile byte[] and Strings of fileName and contentType to our Todo domain object, as shown in Listing 8-5.

Listing 8-5. Updating the Todo Domain Object (in domain/Todo.groovy)

class Todo {

    User owner
    Category category
    String name
    String note
    Date createDate
    Date startDate
    Date dueDate
    Date completeDate
    Date lastModifiedDate
    String priority
    String status
    byte[] associatedFile
    String fileName
    String contentType

    . . .
}

Once you restart the server, it will automatically create the entry in the database as a BLOB, or TINYBLOB if you are using MySQL.


Caution If you are using MySQL, to allow most files to upload, you will need to change the default of TINYBLOB for the database column to LONGBLOB.


The next part is to add a section to our page to upload the file. As shown in Listing 8-6, we add a file upload tag after the due date.

Listing 8-6. The File Upload Tag for the Todo (in views/todo/list.gsp)

<tr class='prop'>
  <td valign='top' class='name'><label for='dueDate'>File:</label></td>>
  <td valign='top'
      class='value ${hasErrors(bean:todo,field:'asociatedFile','errors')}'>
    <input type="file" name="asociatedFile" />
  </td>
</tr>

Performing file uploads also requires a change in the form tag itself. You must change the form to a multipart request. To do this, add the form tag shown in Listing 8-7.

Listing 8-7. The Multipart Tag for the Form (in views/todo/list.gsp)

enctype="multipart/form-data"

Figure 8-6 shows an example of the result of our additions: a to-do being created, with a file selected to upload.

As we said earlier, we are making use of Spring for our file upload capability, and you will see when we update the controller next that there are calls to Spring objects. However, in order to use the Spring objects, we need to add a bean in Spring's resources.xml file. This is where we define Spring resources to be used in Grails. Add the lines shown in Listing 8-8 to conf/spring/resources.xml.

image

Figure 8-6. Choosing a file to upload with a new to-do

Listing 8-8. Adding a Bean to conf/spring/resources.xml

<bean class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <property name="maxUploadSize"><value>1000000</value></property>
</bean>

This bean definition also allows you to specify an optional maximum for the file upload size, so that Spring can prevent too big of a file from being uploaded.

The final step is to actually save the file. This is not too complicated, but it does require making use of some Spring objects. We will cast the request coming in as a MultipartHttpServletRequest and retrieve the items off the file as necessary. Listing 8-9 shows the new method to handle the file upload.

Listing 8-9. The uploadFileData Method on the TodoController (in controllers/TodoController.groovy)

import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
. . .
def uploadFileData = { todo ->
    if (request instanceof MultipartHttpServletRequest) {
        MultipartHttpServletRequest multiRequest
            = (MultipartHttpServletRequest)request;
        CommonsMultipartFile file =
            (CommonsMultipartFile)multiRequest.getFile("associatedFile");
        // Save the object items.
        todo.fileName = file.originalFilename
        todo.contentType = file.contentType
        todo.associatedFile = file.bytes
    }
}

Simply call this method before you persist on your save method in order to set the appropriate properties on the Todo.

Downloading the File

Now that it is stored, we are going to want to be able to retrieve the file on the fly. The file that is returned from the database is in a byte[], hence you can use any common method of response rendering to render the returned item. When you return a file, you put the byte[] into the output stream of the response, setting some header data. A basic example of a file return is shown in Listing 8-10.

Listing 8-10. A Download File Method for TodoController (in controller/TodoController.groovy)

def downloadFile = {
    def todo = Todo.get( params.id )
    response.setHeader("Content-disposition",
        "attachment; filename=${todo.fileName}")
    response.contentType = todo.contentType
    response.outputStream << todo.associatedFile
}

This method can be called by a link on our to-do page, just by passing in the ID of the to-do. As you can see in the method, the header and contentType returns are why we needed to save those two items in the first place.


Caution Later in the chapter, we will switch our to-do add page to be an Ajax form submit. When that happens, you will not be able to upload a file. This is in part due to the way Ajax sends data over to the controller. At that point in our sample application, we will need to move the file upload outside the normal form submit. You can see how that is done in this book's downloadable source code.


Adding Mail Services

Another common feature of web sites is the ability to send e-mail from them. We will add this capability to our application. For right now, we will use the mail service to send an e-mail when a user registers. In Chapter 10, we will use it again to send reports.

If you are familiar with the Spring e-mail service, you will be right at home with the Grails system, since it uses Spring Mail under the covers.


Note There are proposals to make the Grail mail system more DSL-like. If you want to follow the latest developments, check out the Mail from Grails page5.


We will create an e-mail service, and then adjust our user registration process to call it and send an e-mail. This requires the following steps:

  • Create the service to send an e-mail.
  • Create the authenticator to be used for logging in to an SMTP server.
  • Update the Spring resources.xml file.

Creating the E-Mail Service

Because Grails uses Spring's e-mail support, we will be using the org.springframework.mail.MailSender class to actually send the e-mail. In order to make this easier for all of us, we are going to wrap the call to the class in a service. The service will provide an easy generic set of parameters to send the e-mail. That way, the callers do not need to worry about creating MIME messages. Listing 8-11 shows the EMailAuthenticatedService.

__________

Listing 8-11. The EMailAuthenticatedService, Responsible for Sending E-Mail

01. import org.apache.log4j.Logger;
02.
03. import org.springframework.core.io.InputStreamResource
04. import org.springframework.core.io.ByteArrayResource
05.
06. import org.springframework.mail.MailException
07. import org.springframework.mail.MailSender
08. import org.springframework.mail.javamail.MimeMessageHelper
09.
10. import javax.mail.internet.MimeMessage
11. import javax.mail.internet.InternetAddress;
12.

13. class EMailAuthenticatedService {
14.     boolean transactional = false
15.     MailSender mailSender
16.
17.     def sendEmail = { mail, eMailProperties, attachements ->
18.         MimeMessage mimeMessage = mailSender.createMimeMessage()
19.
20.         MimeMessageHelper helper
                  = new MimeMessageHelper(mimeMessage, true, "ISO-8859-1")
21.         helper.from = eMailProperties.from
22.         helper.to = getInternetAddresses(mail.to)
23.         helper.subject = mail.subject
24.         helper.setText(mail.text, true);
25.         if(mail.bcc) helper.bcc = getInternetAddresses(mail.bcc)
26.         if(mail.cc) helper.cc = getInternetAddresses(mail.cc)
27.
28.         attachements.each { key, value ->
29.             helper.addAttachment(key, new ByteArrayResource(value))
30.         }
31.
32.         mailSender.send(mimeMessage)
33.     }
34.
35.     private InternetAddress[] getInternetAddresses(List emails) {
36.         InternetAddress[] mailAddresses = new InternetAddress[emails.size()]
37.         emails.eachWithIndex {mail, i ->
38.             mailAddresses[i] = new InternetAddress(mail)
39.         }
40.         return mailAddresses
41.     }
42. }

On line 15, we have a reference to MailSender. Since this is not set explicitly, you can assume it will be injected by Grails. You will see later how we reference MailSender in Spring's resources.xml file.

The only public method starts on line 17. This will be the method that any clients using the service will use. The parameters passed to it are simple. We are going to send a mail object, which will be passed to the method as a Map.

Creating the Mail Sender

The EMailAuthenticatedSender has a MailSender as an injectable component. This is actually relatively easy to create but does require a few steps. We need to add a few entries into resources.xml and one new service. We are going to work this a bit in reverse—we will build up the top entries, and then go through their dependents.

We begin by defining the mailSender in resources.xml, as shown in Listing 8-12.

Listing 8-12. mailSender Defined in resources.xml

<bean id="mailSender"class="org.springframework.mail.javamail.JavaMailSenderImpl">
  <property name="host" value="smtp.apress.com" />
  <property name="session" ref="mailSession" />
</bean>

As you can see, the mailSender itself defines two variables: a host and a session. The host is a String bean identifying the host we are sending the e-mail through. For a production server, it could very easily be localhost or anther host on the network. In our example, we are using a fictional Apress SMTP server.

The session is a bit more complex and will require us to define another injectable object. So, we need to add another bean, mailSession, in our resources.xml file, as shown in Listing 8-13.

Listing 8-13. mailSession Defined in resources.xml

<bean id="mailSession" class="javax.mail.Session" factory-method="getInstance">
  <constructor-arg>
    <props>
      <prop key="mail.smtp.auth">true</prop>
      <!-- If SSL needed...
      <prop key="mail.smtp.socketFactory.port">465</prop>
      <prop key="mail.smtp.socketFactory.class">
        javax.net.ssl.SSLSocketFactory
      </prop>
      <prop key="mail.smtp.socketFactory.fallback">
        false
      </prop>
      -->
    </props>
  </constructor-arg>
  <constructor-arg ref="smtpAuthenticator" />
</bean>

Here, we have defined the session to work with a non-SSL source, but as you can see by the commented-out code, switching to an SSL source will be quite easy as well.

As you may have guessed, we have yet another item to inject, the smtpAuthenticator. We need to create an object and define the bean for it. First let's define the bean in resources.xml, as shown in Listing 8-14.

Listing 8-14. smtpAuthenticator Defined in resources.xml

<bean id="smtpAuthenticator" class="SmtpAuthenticator">
  <constructor-arg value="[email protected]" />
  <constructor-arg value="xxxxxx" />
</bean>

We have defined a constructor that takes in a username and a password (blanked out because, well, we don't need everyone checking our e-mail).

Now we need to create a bean for this as well. We are going to create this class in the services folder, and will simply extend javax.mail.Authenticator. Listing 8-15 shows our authentication bean.

Listing 8-15. The Custom SmtpAuthenticator Bean

import javax.mail.Authenticator

class SmtpAuthenticator extends Authenticator {

  private String username;
  private String password;
  public SmtpAuthenticator(String username, String password) {
    super();
    this.username = username;
    this.password = password;
  }

  public javax.mail.PasswordAuthentication getPasswordAuthentication() {
    return new javax.mail.PasswordAuthentication(username, password);
  }
}

Updating the Registration Page

Now that our bean and all of its subcomponents have been defined, it's time to put it to use. We will modify the registration page to send an e-mail message. Listing 8-16 shows the method that we will use.

Listing 8-16. Registration Page to Send E-mail (in controller/UserController.groovy)

private sendAcknowledgment = { user ->
    // Let's first design the email that we want to send
    def emailTpl = this.class.classloader.getResource(
        "web-app/WEB-INF/templates/regisrationEmail.gtpl")
    def binding = ["user": user]
    def engine = new SimpleTemplateEngine()
    def template = engine.createTemplate(emailTpl).make(binding)
    def body = template.toString()

    // Set up the email to send.
    def email = [
        to: [user.email],
        subject: "Your Collab-Todo Report",
        text: body
    ]

    try {
        // Check if we "need" attachments
        eMailAuthenticatedService.sendEmail(email, [])
    } catch (MailException ex) {
        log.error("Failed to send emails", ex)
        return false
    }
    true
    }

This e-mail call is actually relatively simple. We will pass in a map defining the To and Subject lines and text. The email message body is generated by using a Groovy template engine on the file registrationEmail.gptl.

Note that you can reuse this code in other places to send e-mail messages.

Tag Libraries

Tag libraries provide sets of custom actions that you perform inside pages. Generally, the actions are repetitive or would be too long to write scriptlets within the page.

You have seen many of the Grails built-in tag libraries in use in our examples so far. We have used these tags to output data, render lists, and so on, and we will continue to use them throughout the book. See the "Grails Tags" section in Chapter 5 for an overview of the Grails tags.

Here, we will cover how to create your own custom tag library. If you have created tag libraries in the past with Java frameworks, you know that it is actually quite a pain. Your tag library class must extend base class. You then need to define the tag and its attributes in your tag library definition. Optionally, you can then reference that tag library in the web.xml. Finally, you reference the specific tag you are using in the page itself. Wow—that's quite a bit of work just to create something that may be only a formatter. Fortunately, creating a tag library with Grails is simpler than that.

You may have noticed that on our application's to-do page, the option to add a to-do is always shown. But users may go to that page and just want to see the list. It would be good to be able to hide the add section and open it when necessary. We can create a tag library to handle this. It will mark an area with div tags and allow the user to click a JavaScript link to open that section. Creating this will require two sets of code segments: one to display the JavaScript and the other to actually call that JavaScript for any div section. Normally, with JSP, this would require two classes and a host of XML. Thanks to Grails, we can handle this with one class and no XML.

Creating the Tag Library

Tag libraries reside in the grails-app/taglib folder, so that is where we will create our new tag library. Listing 8-17 shows the outline of our tag library with all the global objects we will be using.

Listing 8-17. The ShowHideTagLib Outline

class ShowHideTagLib {

}

As you can see, this doesn't contain much, and that's because this is all we need for the basic outline.

We are actually creating two separate tag libraries. While this is normally done with different classes, with Grails, we merely have separate methods. Listing 8-18 shows the methods we are adding to ShowHideTagLib.

Listing 8-18. The Contents of ShowHideTagLib

    def showHide = { attrs, body ->

        def divId = attrs['update']
        out << """<a href="javascript:showhide('$divId'),">${body()}</a>"""
    }

    def preLoadShowHide = { attrs, body ->
        out << """<script language="javascript">
            <!--

            function showhide(layer_ref) {

                // Let's get the state.
                var state = document.getElementById(layer_ref).style.display;

                if (state == 'block') {
                    state = 'none';
                } else {
                    state = 'block';
                }

                if (document.all) { //IS IE 4 or 5 (or 6 beta)
                    eval( "document.all." + layer_ref + ".style.display = state");
                }

                if (document.layers) { //IS NETSCAPE 4 or below
                    document.layers[layer_ref].display = state;
                }
                if (document.getElementById &&!document.all) {
                    hza = document.getElementById(layer_ref);
                    hza.style.display = state;
                }
            }
            //-->
            </script>
        """
    }

Here, we have two tag library calls. Each of them shows how great it is to use Groovy when creating tag libraries.

Since creating tag libraries requires the output of the code to be HTML markups, this generally involves quite a bit of string building. Not only that, but when you have output with quotation marks, you need to escape them with throughout the code. Yuck! However, with Groovy, we can use triple quotes. The triple quote style allows us to not only fully embed strings with markups, but also to return characters and referenced values.

The first method, showHide, passes in two objects:attrs and body. The body is simply the section of the page between the opening and closing bracket of your tag library. The attrs is a map of attributes you want to pass into the method. With regular JSP tag libraries, you need define them individual as getters and setters on the page, and in the tag library XML. With Grails and Groovy, that is not necessary. As you can see, we have mapped a value called update, which is the div tag section we want activated.

The second method, preLoadShowHide, actually doesn't contain any dynamic code per se. We are simply outputting the JavaScript in there.

Referencing the Tag Library

Referencing the tag library is simple as well. By default, the tag library is referenced in the g namespace—the same one in which all the built-in Grails tags are referenced. Then the method name is used as the tag's reference name. Listing 8-19 shows the calls to the tags in todo/list.gsp.

Listing 8-19. Excerpts from todo/list.gsp Showing the Calls to the Custom Tags

<g:preLoadShowHide/>
<g:javascript library="scriptaculous" />
<div class="body">
<h2>Todo List<g:showHide update="addToDo">
    <img border=0 src="${createLinkTo(dir:'images',file:'add_obj.gif')}"
        alt="[ADD]"/>
</g:showHide>

But what if you don't want to use the g namespace? Perhaps you are bundling the application as a tag library and are worried about name conflicts, or you simply want to remember it's not part of the core Grails functionality. In order to change the namespace used, add a static namespace reference in your tag library. For example, to use the namespace todo for our code, you would add the following line to ShowHideTagLib:

static namespace = 'todo'

Ajax in Grails

We certainly could not have a Web 2.0 chapter without including a discussion of Ajax. Ajax stands for Asynchronous JavaScript and XML, which oddly enough, is not a 100% accurate definition. Although Ajax is usually asynchronous, usually written in JavaScript, and often deals with transmission of XML, none of these items is a must for it. You can send Ajax messages synchronously, you do not have to use JavaScript to send them, and your response can be an XML file but can also be a regular string.


Note The term Ajax was originally coined by Jesse James Garrett. But the technology was first developed by Microsoft in an attempt to deal with remote scripting.


One of the biggest "secrets" about Ajax is that, for the most part, it's really not that complex, at least conceptually. There is nothing you can do with Ajax that you could not do in a normal application; however, using Ajax can help your application not only perform better, but also give a richer user experience.

The core of Ajax is just sending data to the server and parsing the data on the return without forcing the display to refresh. The complexity lies in making use of the data, and this is where you start to see frameworks emerge. The fact is that these frameworks are not 100% Ajax—if they were, they wouldn't be very big. Instead, these frameworks wrap Ajax with JavaScript UI enhancements. Some of the calls won't even involve Ajax. However, here we will refer to these frameworks as Ajax frameworks.

Using Ajax Frameworks in Grails

Popular Ajax frameworks include Prototype, Dojo, script.aculo.us, and Yahoo! User Interface (YUI) Library. Even Google has come onboard with its own rather complex Ajax framework, Google Web Toolkit (GWT).

Most of the popular web frameworks have implemented Ajax. The majority of these did not create their own Ajax framework, but merely wrapped code from previous Ajax frameworks. Ruby on Rails uses script.aculo.us, Tapestry's Tacos uses Dojo, and so on. So what does Grails use? The answer is all of the above.

In an effort to provide maximum flexibility, Grails currently accepts all of the frameworks out there. So what does this mean? Is this good or bad? It's a bit of both. While it allows us more flexibility in choosing a framework, in the end, we need to write more code than other frameworks usually demand, especially when it comes to the JavaScript UI portions of the Ajax items. If you are familiar with other Java or Rails Ajax uses, this will become apparent to you in the upcoming examples.

Using an Ajax framework is relatively simple. You define at the top of your page(or in the main page) which Ajax framework to use with a <g:javascript> tag. The following define Prototype, YUI, script.aculo.us, and Dojo, respectively:

<g:javascript library="prototype" />

<g:javascript library="yahoo" />

<g:javascript library="scriptaculous" />

<g:javascript library="dojo" />

The only slight difference is if you want to use Dojo. Since Dojo is a notoriously large framework, it has not been included by default with Grails. You will need to download and install it with the following command:

> grails install-dojo

Each of these frameworks has its own custom UI components. If you are familiar with Rails or Tapestry's Tacos, you know that they generally provide complete support for the underlying framework. In other words, there is usually a tag library wrapper for the whole framework. This makes it easy to not only support the Ajax components, but also the JavaScript components. Unfortunately, this is not the case in Grails. Grails supports just the standard Ajax components, as listed in Table 8-1. However, this does give us a good subset of components to use.

Table 8-1. Ajax Components in Grails

Tag Description
remoteField Creates a text field that sends its value to a remote link when it changes
remoteFunction Creates a remote JavaScript function that can be assigned to a DOM event
remoteLink Creates a link that calls a remote function
formRemote Creates a form that executes an Ajax call on submission
javascript Loads a JavaScript function
submitToRemote Creates a button that submits the form as an Ajax call

For our examples, we are going to use script.aculo.us. We chose this framework because it supports the UI features we want to use. Also, since Grails is often compared to Ruby on Rails, which uses script.aculo.us, we thought that using the same Ajax framework would help provide a more direct comparison.

Now we will use Ajax to spice up our to-do page. We will go over three basic examples:

  • Rendering parts of pages with form submissions
  • Editing a field in place dynamically
  • Showing a drop-down list of choices while typing in place (using the autocomplete feature)

Some of these will be simpler than others to implement. These examples will give you a good starting point for creating your own Ajax components.

Dynamic Rendering of Data

Our first example demonstrates using one of the most basic and popular types of Ajax components. This is where you type data into the page, submit it, remotely call the server, process the data, and re-render only a portion of the page. For our example, we are going to modify the to-do add page to do a partial page re-rendering. Now when adding a new to-do, instead of doing an entire page refresh, the page will dynamically render the to-do list section of the page.

In order to perform this, we need to take a few steps, the first of which is not necessarily Ajax-specific:

  • Move the list section of the page into its own page (called a template or partial page).
  • Change our current add call to do an Ajax remote call instead of submitting the whole page.
  • Change the TodoController's return to render the new page we created instead of the whole page.

Note One of the big issues you will run into when performing the dynamic rendering of data is partial page updates. Partial page updating refers to re-rendering a part of the page. Some frameworks, like Tapestry's Tacos, allow you to perform this in line. However, the majority of web frameworks, including Grails and Ruby on Rails, force you to call to another page. In reality, this is not a big deal. It does add to the number of GSPs you need to write, but on the plus side, it keeps the GSPs clean.


Rendering a Template

Rendering a page from another page is actually fairly simple. First, we need a page to call from, which obviously must be a GSP page. We will use the <g:render /> tag library to define the area of the page that will be calling out to another GSP page. Grails refers to these partial pages as templates.

Our first step is to take our list of to-dos in todo/list.gsp and pull that section out to its own page. We will replace the list with what is in Listing 8-20. Also, instead of taking the entire code, we will take everything but the for loop. This is because we can tell the renderer to render a collection.

Listing 8-20. A Template of todo/list.gsp with the Modified To-Do List Display

<div id="todoList">
  <g:render template="detail" var="todo" collection="${todoList}" />
</div>

Here, we simply tell Grails to take our collection labeled todoList and iterate through the list, rendering the detail page each time for every item in the collection. The item in the collection is then referenced in the page by the variable var.


Caution By default, the var field is optional. If you did not use the field, you would be able to access the information in the template using the reserved word it. However, while this does work, it can present problems if your template references other templates or other tag libraries. So we suggest that you always use var when creating the renders.


Creating a Template

The name of the page we are creating will not actually be detail.gsp. Instead, Grails chooses the page to render by taking the rendered template attribute and adding underscores at the beginning to indicate the page is a template. The page must also be located in the same directory as the calling controller. Thus, for this example, we will create _detail.gsp in the todo directory, as shown in Listing 8-21.

Listing 8-21. The _detail.gsp Page

<div id="todoDetail${todo.id}" class="todo">

  <div class="todoTitle">${todo.name?.encodeAsHTML()}
     <g:link action="edit" id="${todo.id}">
         <img border=0
           src="${createLinkTo(dir:'images',file:'write_obj.gif')}" alt="[EDIT]"/>
    </g:link>
     <g:remoteLink
             action="removeTask"
             id="${todo.id}"
             update="todoDetail$todo.id"
             onComplete="highlight('todoDetail$todo.id'),">
         <img border=0 src="${createLinkTo(dir:'images',file:'delete_obj.gif')}"
             alt="[EDIT]"/>
     </g:remoteLink>

      <g:showHide update="todoDetailFull${todo.id}">
      <img border=0
               src="${createLinkTo(dir:'images',file:'add_obj.gif')}"
                alt="[Show All]"/></g:showHide>

  </div>

  <div id="todoDetailFull${todo.id}" class="todo" style="display:none">
    Status: ${todo.status?.encodeAsHTML()} <br />
    Priority: ${todo.priority?.encodeAsHTML()} <br />
    Created date: ${todo.createDate?.encodeAsHTML()} <br />
    Last Modified date: ${todo.lastModifiedDate?.encodeAsHTML()} <br />

    <g:if test="${todo.completeDate == null}">
        Complete Task: <input type="checkbox"
                              onclick="${remoteFunction(
                                            action:'completeTask',
                                            id:todo.id,
                                            update:'todoDetail' + todo.id,
                                            onComplete:'highlight('todoDetail' + todo.id+'')' )};"/> <br />
    </g:if>
    <g:else>
        Completed Date: ${todo.completeDate?.encodeAsHTML()} <br />
    </g:else>
      <!-- show notes -- mark in the code that we should use a todo -->
      <g:radeoxRender>${todo?.note}</g:radeoxRender>
    <!-- update:[success:'great', failure:'ohno'], -->
      <!--
    <g:remoteLink action="showNotes" id="${todo.id}"
         update="todoDetailNote${todo.id}">
        Notes
    </g:remoteLink><br/>
    <div id="todoDetailNote${todo.id}">
    </div>
    -->
  </div>

</div>

Our first step is complete. In reality, there is nothing in the page that is Ajax-enabled yet. Right now, the page works exactly as it did before, and in theory, you could have used these techniques to help segregate the code.

Making the Page Dynamic

Now we will do the partial page form rendering, which is a two-step process:

  • Change the form to take an Ajax form tag.
  • Have the save call on the controller render the tag instead of the whole page.

For the first part, change the form encapsulation in list.gsp to the code shown in Listing 8-22.

Listing 8-22. Adding an Ajax Form Tag (in views/todo/list.gsp)

<g:formRemote name="todoForm"
              url="[controller:'todo',action:'save']"
              update="todoList"
              onComplete="showhide('addToDo')"
              enctype="multipart/form-data">
   . . .
</g:formRemote>

This calls the save action on our TodoController and then on completion, hides the add section. In addition, the update attribute will tell us which <div> section we are updating. In Listing 8-21, notice that we surrounded our rendered items with the <div> tag todoList. This will be the section that the Ajax JavaScript will re-render upon return.

The changes to the save action are equally as easy. Instead of the standard return, where we redirect to the list page, we have a line to get the collection and call out to render the GSP we marked, as shown in Listing 8-23.

Listing 8-23. Rendering Just the Tag (in views/todo/list.gsp)

render(template:'detail',  var: 'todo', collection:listByOwner())

As you can see, besides having to move some data, this was all relatively simple as can be. And that is all that is needed. If you go back to the page now, it will do an update without needing to return the whole page.


Note In the downloadable code, you will find that we have also changed the buddy list sections to do partial page re-rendering. So when you create a new buddy list or add a buddy to a list, those sections will be re-rendered as well.


Editing a Field in Place

The previous example involved editing an entire form; however, this is not always necessary. Sometimes all we need is to alter one field, or we want to allow users to update one field at a time.

In our application, when you add a buddy, the nickName (which is the name displayed on the screen) stored in BuddyListMember defaults to the name of the buddy. What if you wanted the nickName to be something different? It would be a bit silly to have to go all the way to an edit page just to change one field. Also, what if, in the case of buddy list members, you had many buddies in different lists that you wanted to update quickly? The easiest way would be to just click the name and be able to change the name on the fly. In this section, we'll add editing-in-place capabilities for these items.

In the previous section, we relied entirely on the Grails Ajax tag libraries. In fact, the previous code would have not changed whether we used script.aculo.us, Dojo, or another Ajax framework. However, that all changes for this and the following section, where we will be making use of calls specific to script.aculo.us.

For our example, we are going to use the buddy list name itself, although this will work with any of the dynamic fields on the page. When you click the name, the name will switch to an input box with ok and cancel buttons.


Note As we mentioned earlier, we have also implemented the dynamic rendering for the buddy list and the buddies. This is why the GSP code is in a different place than in previous chapters.


First, let's update the code. The code in question is in common/_buddyList.gsp. So we will change it from a regular display to a custom tag library, as shown in Listing 8-24.

Listing 8-24. The Buddy List Name Display Updated for Editing in Place (in views/common/_buddyListMember.gsp)

<g:editInPlace id="buddyListName${list.id}"
               url="[controller: 'buddyList', action: 'editName', id:list.id]"
               rows="1"
               cols= "10"
               paramName="name">${list.name}</g:editInPlace>

Our custom tag library will be defining a few items: the ID of the area we are updating, the standard URL, and the parameter from the body of the text that will be passed through. The rows and columns are used to define the size of the input box itself.


Tip If you are developing an application where the field could potentially be very small or very large, you may want to create a method in the tag library that would dynamically size it based on the text length.


Let's move on to the tag library itself, which is shown in Listing 8-25.

Listing 8-25. The AjaxTag Library with the editInPlace Method

class AjaxTagLib {

    def editInPlace = { attrs, body ->
        def rows = attrs.rows ? attrs.rows : 0;
        def cols = attrs.cols ? attrs.cols : 0;
        def id = attrs.remove('id')
        out << "<span id='${id}'>"
        out << body()
        out << "</span>"
        out << "<script type='text/javascript'>"
        out << "new Ajax.InPlaceEditor('${id}', '"
        out << createLink(attrs)
        out << "',{"
        if(rows)
            out << "rows:${rows},"
        if(cols)
            out << "cols:${cols},"
        if(attrs.paramName) {
            out <<  """callback: function(form, value) {
                return '${attrs.paramName}=' + escape(value) }"""

        }
        out << "});"
        out << "</script>"
    }
}

As you may have noticed, we took the script.aculo.us call and converted it into a tag library. There's nothing too complex here, but it makes the page much more readable in the end.

The final step is the creation of the method to actually change the name. This method will be located in the BuddyListController, and will update the buddy list with a new name, save it, and re-render the section. Listing 8-26 shows this editName method.

Listing 8-26. The editName Method in the BuddyListController (in controller/BuddyListController.groovy)

def editName = {

   log.info "Update buddy list name"

   // Retrieve member
   def buddyList = BuddyList.get(params.id)
   buddyList.name = params.name

   // Render a new page.
   render params.name
}

Now let's take a look at this method in action. Figure 8-7 shows what happens after you click a buddy name.

image

Figure 8-7. Editing in place

After you click ok, you will see indications that the changes are being applied (a "working" icon and then some highlighting), and then the update will be made. Figure 8-8 shows an example of changing "Co-Workers" to "Fav Workers."

image

Figure 8-8. The buddy list name is changed to Fav Workers.

As you can see, this code is fairly simple, and with the tag library, we can easily insert this logic anywhere into our application.

Using the Autocomplete Feature

The final Ajax feature we will add is dynamic rendering of drop-downs. This is another fairly new and cool feature being employed by web sites. The autocomplete feature allows a drop-down list of matching selections to be displayed and updated as the user types. This can be good for helping users complete an entry that must be exact. Here, we will use this feature for adding buddies to an existing buddy list.

Figure 8-9 shows an example of how autocomplete will work once we have completed this example, On the page, we expanded the add section and started to type in the text field, beginning with the letter j. In this case, since each of the authors' names (first or last) starts with a J, it found all of us. From here, you can select the buddy you want to add and press Enter, and he will be added to the list.

image

Figure 8-9. Our drop-down box after typing in "j"

Before the Ajax functionality, there was a simple form submit. We are going to adjust this using two techniques we have already covered: change the form to a <g:formRemote> tag and use an Ajax call specific to script.aculo.us. Listing 8-27 shows the added remote form tag, complete with the definition of the area we are going to update.

Listing 8-27. The Remote Form Call for Adding a Buddy to the Buddy List (in views/common/_buddyList.gsp)

<g:formRemote name="buddyListForm${list.id}"
              url="[controller:'buddyListMember',action:'add']"
              update="buddyListMembers${list.id}"
              onComplete="showhide('buddyListAdd${list.id}')">
    . . .
</g:formRemote>

Now we get to the script.aculo.us part. Here, the code can get a bit trickier. We are going to adjust the input text box to have an ID assigned to it. After that, we will start an Ajax call to monitor any input to it. If text is typed, it will make an Ajax call and create the drop-down list you saw in Figure 8-8. The code that performs this operation is shown in Listing 8-28.

Listing 8-28. Ajax Code to Create the Dynamic Drop-Down (in views/common/_buddyList.gsp)

<span id="indicator1" style="display: none">
  <img src="/collab-todo/images/spinner.gif" alt="Working..." />
</span>
<div id="autocomplete_choices${list.id}" class="autocomplete"></div>

<script type="text/javascript">
  new Ajax.Autocompleter("autocomplete${list.id}",                          "autocomplete_choices${list.id}",
                         "/collab-todo/user/findUsers",
                         {afterUpdateElement : getSelectionId${list.id}});

  function getSelectionId${list.id}(text, li) {
    document.buddyListForm${list.id}.userNameId.value = li.id;
  }
</script>

Since our methods no longer redirect to a new page, we need to change the final render so that it renders the buddy list subpage again. This is accomplished with the line of code shown in Listing 8-29.

Listing 8-29. Rendering the Subpage (in views/common/_buddyList.gsp)

render(template:'/common/buddyListMember',  var: 'buddy',
       collection:BuddyListMember.findAllByBuddyList(member.buddyList))

Since we are doing a dynamic lookup of names, this is not the only method we need. We will create a new method that will use the Criteria query operation, similar to the one we looked at in Chapter 6. This method will find the users based on what the user is typing and will look for the first name, last name, or username, and then return the list, as shown in Listing 8-30.

Listing 8-30. The UserController findUsers Method (in controller/UserController.groovy)

def findUsers = {
    // Let's query the database for any close matches to this
    def users = User.createCriteria().list {
        or {
            like("userName", "%${params.userId}%")
            like("firstName", "%${params.userId}%")
            like("lastName", "%${params.userId}%")
        }
        order("lastName")
        order("firstName")
    }

    // Let's build our output XML
    def writer = new StringWriter()

    // Build it
    new groovy.xml.MarkupBuilder(writer).ul {
        for (u in users) {
            li(id: u.id, "${u.lastName}, $u.firstName")
        }
    }
    render writer.toString()
}

The Criteria query was only half of the work. The other half is to tell the browser how to render the information we are passing back. By default, for autocomplete, script.aculo.us expects an unnumbered list to be returned to it. Once it receives that, it can properly parse the return. Luckily for us, there is a really easy way to create an unnumbered list or any XML with Groovy. We can use the MarkupBuilder to create a bulleted list of unordered elements, so that the string returned in Listing 8-30 will actually look like the following:

<ul>
<li>Nusairat, Joseph</li>
<li>Judd, Chris</li>
<li>Shingler, Jim</li>
</ul>

Now we have one final task to perform. If you have been coding along with the example, and have entered the code and tried to render it, you will get a drop-down list, but it will be difficult to read. This is because the default style is used. The solution to this is quite simple: for the autocomplete items, we will create a CSS style that will help set it apart. We will use yellow with some bold when highlighting, as shown in Listing 8-31.

Listing 8-31. CSS Style Addition for the Dynamic Drop-Down (in main.css)

div.autocomplete {
  position:absolute;
  width:250px;
  background-color:white;
  border:1px solid #888;
  margin:0px;
  padding:0px;
}
div.autocomplete ul {
  list-style-type:none;
  margin:0px;
  padding:0px;
}
div.autocomplete ul li.selected { background-color: #ffb;}
div.autocomplete ul li {
  list-style-type:none;
  display:block;
  margin:0;
  padding:2px;
  height:32px;
  cursor:pointer;
}

Once you have updated the main.css file, your code should render correctly and save correctly as well.

RSS Feeds

RSS feeds have become an increasingly popular feature to incorporate on a web site. What has contributed to RSS feed popularity is the increasing number of RSS readers out there, including the new iGoogle6 and the RSS Web Clip in Gmail. So we are going to go over creating a basic RSS reader. This will be an extremely basic example; in a real-world application, you would want to add more items for security checking.

Creating an RSS feed basically requires creating an XML output in a fairly strict format. The reader then takes that XML and parses it for content.

We could do this by hand, but the format based on the feeds can be somewhat complex, and you would also need to write quite a bit of repetitive code. Luckily, there is as plug-in that will help us cheat a bit and create the feeds. The Feeds plug-in7 supports creating feeds in the popular RSS and Atom formats (with multiple versions of each supported). Start by installing the plug-in:

> grails install-plugin feeds

__________

The next step is to create a controller with one method in it. This method will be rendering the XML in a way that the renderer can understand. For this example, we will use the Atom format to format the output. Listing 8-32 shows our RSSController with a feed method.

Listing 8-32. Our RSSController with the feed Method (in controller/RssController.groovy)

import feedsplugin.FeedBuilder

class RssController {

    def feed = {
        render(feedType:"atom") { // optional - , feedVersion:"2.0") {
            title = "Todo List"
            link = http://localhost:8080/collab-todo/rss

            Todo.list(sort: "name", order: "asc").each {
                def todo = it
                entry(it.name) {
                    title = "${todo.name}"
                    link = "http://localhost:8080/collab-todo/todo/view/${todo.id}"
                    author = "${todo.owner.lastName}, ${todo.owner.firstName}"
                }
            }
        }
    }
}

Here we use a standard renderer, and in it we define a few items. We define the title and the link. Then we iterate through a list of items queried from the database sorted in ascending order. For each item, we need to define an entry. The entry has three items on it: the title for it, a URL link for it, and its contents. Table 8-2 lists a few of the common fields you would expect to have in a feed.

Table 8-2. Some Common Fields for a Feed

Field Name Description
publishedDate The date the entry of the field is published
categories The list of categories related to the entry
author The name of the author of the entry
link The link to a full description of the entry
title The title of the entry

In our example, we used title, link, and author. We sorted based on creation date (actually, we could have sorted based on anything). Note that if you supply publishedDate, then your feeder may automatically sort on that date instead. An example of the output for this example is shown in Figure 8-10.

image

Figure 8-10. Our RSS reader in a Safari browser

Summary

This chapter was the start of transforming our working to-do application into a more robust application. We added features that not only make it more useful, but also make it more visually appealing as well as easier to use. These characteristics are extremely important for a web site.

Consider two web sites that both let you monitor your money: http://www.mint.com and https://moneycenter.yodlee.com. The latter, in our opinion, is far more useful and has more features. However, most people enjoy mint.com, simply because it is more user-friendly and eye-catching. As you develop Grails (and other) applications, keep that in mind. Sometimes what makes a site a winner is not what it has, but how easy and enjoyable it is for the users.

The purpose of this chapter was to expose you to a variety of more advanced web-styling techniques for our application. There are more Ajax techniques and plug-ins available on the Grails site. We suggest taking a peek to see if any meet your needs. And if they don't, you always have the option of creating your own plug-in and joining the Grails community that way.

In the next few chapters, we will expand the to-do application and add even more functionality, including reporting and batch jobs.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset