F0720E8F-2336-4FEE-BB96-7F8FA9B9FD9C.jpg

This is the third post in a series of post about grails. In this series I am describing an application I am creating with grails. It is a scheduling application for scheduling people on projects. You can find the previous posts here:

In this post I will discuss the following topics:

  • Creating meeting notes using the grails-ui rich text editor
  • Create a search using the searchable plugin on the meeting notes
  • Introducing rss to subscribe to new meeting notes


Meeting notes

Create the basics

For the meeting notes we want a large text field that can contain html to make it look better. We start of with the domain object. We give it three fields: a weekNr a User and the notes. The notes field must become a Text field in the database and a textarea on the screen. To accomplish this, we add a mapping element with the following contents as well as the constraints to make it an html textarea element. (Yes I know this feels strange)

class MeetingNotes {
    int weekNr
    User user
    String notes
    static constraints = {
        notes(blank:false, widget:"textarea")
    }
    static mapping = {
        notes type:"text"
    }
}

Next step is the controller, for now we add the scoffold property and configuration to add it to the navigation. The next code block shows the first implementation.

class MeetingNotesController {
    def scaffold = true

    static navigation = [
            group: 'tabs',
            order: 110,
            subItems: [
                    [group: 'tabs', action: 'create']
            ]
    ]
}

The create screen now looks like this:

Screen shot 2010-01-09 at 17.16.59.png

Use the rich text editor

In include the rich text editor, we generate the views and make changes to those. Than we change the create.jsp in views/meetingnotes. We start by removing the navigation. Than we add the following line to the head element.

<gui:resources components="richEditor"/>

Then we just need to make a small change to the gsp. Look for the line with g:textArea. We replace this input item with the following line.

<gui:richEditor id='notes' value='add your weekly notes here ....'/>

This results in the following screen:

Screen shot 2010-01-09 at 18.01.22.png

The same changes need to be made to the edit.gsp. I also removed the navigation from the other gsp’s. Time to move on, now we are going to include the searchable plugin and make the weekly meeting notes searchable.

The searchable plugin

Let us start with the basics and install the plugin, configure the MeetingNotes domain class to be searchable, and look at the generated search screen. You can find these steps as well in the quick start from the plugin documentation.

grails install-plugin searchable

Now the hard part to make our MeetingNotes searchable, we have to add the following line to the MeetingNotes domain class.

static searchable = true

For real, that is it. Now you can browse to the controller that serves the search.

I have created three items that all contain data, the following screen shows the standard search controller. Only two items will be returned if I look for the project name cqrs4j

Screen shot 2010-01-10 at 09.59.29.png

That is all nice, but it does not really integrate with our site. Therefore we want to make a controller that does the search thing and an input box beneath the header menu.

First I add a line to the UrlMappings that maps the /search request to the SearchableController that comes out of the box. Check the file UrlMappings.groovy in the conf folder.

"/search" (controller:"searchable")

Now we will override the view of that comes with the plugin and make it look more like our own. This page, Controller and view, describes how you can do that. I copied the index.gsp from the path ${user.home}/.grails/1.2.0/projects/MyScheduling/plugins/searchable-0.5.5/grails-app/views/searchable/index.gsp to the same location in my own application. Then I alter that index.gsp, add the template, remove some styling and I have a better looking page. I also copied the form into the main.gsp layout so we have a search box on each page. The following screendump shows the result.

Screen shot 2010-01-10 at 10.49.38.png

There you have it, basic search implemented in our own application. Looking really integrated.

There is topic that I also want to mention, this is suggestions. You know them from google and more advanced search solutions. You know what, we have an advanced search now as well. We just have to configure that we want to use suggestions. With this option configured, the results page shows a link to try the search again with suggestions. As an example try to search for holday, you get no results, try the suggestions and you get the following screen.

Screen shot 2010-01-10 at 11.02.28.png

To do this, we change the searchable part of the MeetingNotes into the following lines:

    static searchable = {
        spellCheck "include"
    }

The search plugin has a lot of options and functionality. I urge you to have a look at the plugin page.

Rss feed

A very often method used to be informed for new items is rss. I want to create a feed for all meeting notes. That way people get notified when a new Meeting Note is created. To create the feed, I use the feeds plugin.

Again it all starts with the installation of the plugin. The plugin makes use of the framework Rome. So if you are familiar with that, this should not be to hard. Not that it is hard if you do not have the knowledge.

grails install-plugin feeds

Now adding the feed consists of two parts. The first part is to add a feed method to the MeetingNotes controller. The second part is two add the special html tag, which is done using a grails tag.

<feed:meta kind="rss" version="2.0" controller="meetingNotes" action="feed"/>
    def feed = {
        render(feedType:"rss", feedVersion:"2.0") {
            title = "Meeting Notes feed"
            link = "${grailsApplication.config.grails.serverURL}/meetingNotes/feed"
            description = "All meeting notes that have been written per week"
            MeetingNotes.list().each() { note ->
                entry("weekNr : ${note.weekNr}") {
                    link = "${grailsApplication.config.grails.serverURL}/meetingNotes/show/${note.id}"
                    "Meeting notes for week number ${note.weekNr} by ${note.user.userRealName}" // return the content
                }
            }
        }
    }

The code is so easy I hardly need to explain anything. One thing that had a problem at the moment is hard wiring the name of the server to get the feed from. The only trick I want to point out is the way to construct the link (line 4 and 8). We use the special mechanism to read parameters from the config that can be environment specific. The grails.serverURL parameter is by default configured in the Config.groovy configuration file.

In safari I now have the following result.

Screen shot 2010-01-10 at 12.00.01.png

That is it for this post. I am still amazed by how easy things are using grails. Most of the time I spend on getting the ui done. In the next post I will not introduce new plugin, but I will focus on getting the solutions better. Add validation, better configured access control, internationalization. Those kind of topics.

Hope to see you back.

Tagged on:             

4 thoughts on “Still doing grails

  • January 20, 2010 at 4:51 am
    Permalink

    Oh, well. That didn’t work. Here it is without the leading and trailing lt and gt:

    gui:richEditor id=’notes’ value=’add your weekly notes here ….’/

    • January 20, 2010 at 2:34 pm
      Permalink

      THanks, I corrected the code, now you should be able to see it. Appreciations for letting me know

  • January 20, 2010 at 4:47 am
    Permalink

    Nice, simple tutorial!

    I have one little fix, for you. In the section where you replace the g:textArea with the rich editor, the gui:richEditor tag isn’t displaying (at least in Firefox) because the tag text isn’t encoded (lt, gt, etc.). I’ll include the hidden text below and maybe it will be encoded within the comment so that other readers can see it prior to the problem being fixed in the post itself.

  • Pingback: Random Links #108 | YASDW - yet another software developer weblog

Comments are closed.