Grails Cookbook - A collection of tutorials and examples

Grails Example Application - Simple Ajax Chat

This is an example application that implements a simple group style chat. It shows simple usage of default Grails Ajax Tags. The final output will look like this:
d1
d2

The first screen is to register the user's nickname. After submitting, the chat page will appear where users can start chatting. The messages is displayed at the top, and the user can enter messages at the bottom.
WARNING: Since Grails 2.4.X AJAX related tags are deprecated.

Domain

There is only one domain class for the application:

package asia.grails.simplechat
class Message {
    String nickname
    Date date = new Date()
    String message
}
This model/table will accumulate the chat message logs. Then the application will just select the last few messages to display in the screen of the user.

Registration

For registration, here is the controller and view

package asia.grails.simplechat
class ChatController {
    def index() {
    }
    def join(String nickname) {
        if ( nickname.trim() == '' ) {
            redirect(action:'index')
        } else {
            session.nickname = nickname
            render (view: 'chat')
        }
    }
}

index.gsp

<!DOCTYPE html>
<html>
<head>
    <meta name="layout" content="main"/>
    <title>Simple Chat</title>
</head>
<body>
<g:form action="join">
    <label for="nickname">Please enter your name</label>
    <g:textField name="nickname"/>
    <g:submitButton name="Join Chat"/>
</g:form>
</body>
</html>

The entry point to the application is the action index, which renders the page that contains the registration form index.gsp. The view shows a simple usage of a form. Notice that parameters submitted sent to the server side can be automatically mapped by name. Since the action join has a parameter String nickname, the control <g:textField name="nickname"/> will be mapped to it.
Notice also that we have access to the session map and we can put objects into it.

Chat

For the chat page, here are the contents of the controller and views:

package asia.grails.simplechat
class ChatController {
    def retrieveLatestMessages() {
        def messages = Message.listOrderByDate(order: 'desc', max:10)
        [messages:messages.reverse()]
    }
    def submitMessage(String message) {
        new Message(nickname: session.nickname, message:message).save()
        render "<script>retrieveLatestMessages()</script>"
    }
}

chat.gsp

<!DOCTYPE html>
<html>
<head>
    <meta name="layout" content="main"/>
    <title>Simple Chat</title>
    <g:javascript library="jquery"/>
</head>
<body>
<div id="chatMessages"></div>
<input type="text" id="messageBox" name="message" onkeypress="messageKeyPress(this,event);"/>
<div id="temp"></div>
<script>
    function messageKeyPress(field,event) {
        var theCode = event.keyCode ? event.keyCode : event.which ? event.which : event.charCode;
        var message = $('#messageBox').val();
        if (theCode == 13){
            <g:remoteFunction action="submitMessage" params="\'message=\'+message" update="temp"/>
            $('#messageBox').val('');
            return false;
        } else {
            return true;
        }
    }
    function retrieveLatestMessages() {
        <g:remoteFunction action="retrieveLatestMessages" update="chatMessages"/>
    }
    function pollMessages() {
        retrieveLatestMessages();
        setTimeout('pollMessages()', 5000);
    }
    pollMessages();
</script>
</body>
</html>

retrieveLatestMessages.gsp

<g:each in="${messages}" var="message">
    <div>
        <span class="nickname">${message.nickname}</span> - <span class="msg">${message.message}</span>
    </div>
</g:each>

Look at chat.gsp first. What it does is to continuously request from the server for the latest messages. That is what the functions retrieveLatestMessages and pollMessages does.
The remoteFunction is the one that invokes an AJAX request to the server. Which is received by retrieveLatestMessages action in the controller. The controller action just retrieves the last 10 messages and renders the result in retrieveLatestMessages.gsp.
For sending chat messages, the keypress event of the textbox is monitored. When ENTER key is pressed (code = 13), then the content of the text box is sent to the server and the message is logged to the database. To refresh the message list immediately, we return code back to invoke a retrieveLatestMessages automatically.

Default Page

If you want to have the chat page as the default landingpage of the application, just configure it in UrlMappings. For example:

class UrlMappings {
	static mappings = {
		"/$controller/$action?/$id?"{
			constraints {
				// apply constraints here
			}
		}
        "/" (controller:"chat", action:"index")
		"500"(view:'/error')
	}
}

This just says that when the root of the application is access /, then the index action of chat controller is invoked.

Remarks

The above code is just to serve as an example. It has many loop holes like missing validations and performance due to polling. It's purpose is just to show how easy it is to implement rich experience using Grails.
The full source code for this example can be viewed here or can be downloaded here.

List of Example Applications
  • Simple Ajax Chat
  • Simple Document Management System
  • Save Documents To Database
  • Download / Export Excel File
  • Download / Export ZIP File
  • Grails Forum Application

  • Tags: Ajax, Chat, example, remoteFunction