Smarter Grails Tags
While the tags in grails provide a lot of useful features, there is room for improvement. This page outlines some ideas for improvements of the different tags. Feel free to expand this article to other tags.
Form Tags
The biggest area for improvement is with form tags. This is one area the grails tags seem to provide less functionality then other web frameworks. The improvements suggested here are to do with automatically rendering specific classes on input tags when in error and fetching the correct field value instead of having to do these things with function calls in expressions for each tag.
For example, the following tag which is pretty standard for all grails applications:
<g:textField name="username" value="${fieldValue(bean:user,field:'username'}" class="${hasErrors(bean:user,user:'username', 'errors')}" />
Would be replaced with one of the following:
<g:textField bean="user" field="username" />
or
<g:textField name="user.username" />
The first suggested replacement tag is probably more in line with the grails standard. It specifies the bean and field for which the tag applies. The second example is taken from other web frameworks like Stripes which performs automatic data binding for selected objects on its version of controllers. It probably isn't appropriate for the grails taglib but provides the inspiration for the suggested change.
The replacement tags suggested should operate exactly as the example tag given. It should fetch its value from the correct place on the bean and would result in the rendered html tag having a class of error when there is an error for that field on the bean. This approach has a couple of advantages. The first is that basic and common tag functions used so often with grails form input tags like fetching a field's value and rendering an error class are handled transparently. The second is, while these behaviors are available to make the writing of forms in grails easier, you can always use an alternative method. Other attributes such as maxlength can also be automatically populated for textFields where the constraint maxSize is specified (See http://www.javathinking.com/?p=70 for more information).
Rendering Tags
The suggestions for render tags are born out of the way I personally deal with navigation and sorting on a list page. Given this, I'll start by explaining how I deal with navigation before presenting my suggestions.
In my grails applications, I have a navigation command I like to use. The source is below.
class NavigationCommand implements Serializable { Integer max = 20 Integer offset = 0 String sort = "" String order = "asc" }
I like being able to separate this parameters away from the logic of an action*. There is a down side of this approach though. In my actions, I have to copy across he values from the command to the params in my action so the paginate and sortableColumn tags can have access to them. Born from this frustration is the following suggestion. Tags like paginate and sortableColumn should have a bean attribute where it first looks for the parameters it needs. For example, to use my navigation command assuming I have the following list action:
def list { NavigationCommand nav ->
// Some code
...
[ total : total, ..... ]
}
I should be able to use the following tag:
<g:paginate total="${total}" bean="${nav}" />
The paginate tag would fist look at the nav bean for max, offset etc. before checking params. This can also be applied to other tags like sortableColumns.
* NOTE: Another reason for separating the navigation into a separate command is that I use a custom paginate tag that allows a user to set how many rows they can view on a page. Having this meant I was constantly dealing with max and offset in my params which started to become a pain. A screen shot of my custom paginate page is in attachments. If you like it, maybe it could also be added into grails.
Comments (3)
Feb 22, 2008
Kristian Mandrup says:
Yes, this approach has been take successfully by a lot of other frameworks and s...Yes, this approach has been take successfully by a lot of other frameworks and seems to make sense somewhat.
On the other hand, use of the "class" is more like a Decoration, and the logic behind the Decorator decision can quickly become more complex. It would make more sense to allow externalization og this Decorator logic, making it independant of the UI and more flexible.
The bean-mapping is more tightly coupled to the form control so it makes perfect sense to have the binding expressed directly in the tag.
I imagine that the controls could be set to different states depending on the state of some underlying model. The states could then be mapped (Layout-mapping.config?) to certain CSS classes or some other annotation/decoration of the control.
Fx:
formGroup "interview" {
state "null" {
default "error"
form.input "error-star"
}
state "validated" {
default "ok"
form.input "ok-check"
}
}
formGroup "login" {
...
}
or something similar. Then I can opt to change the state-to-class mapping across a select set of forms (belonging to a named formGroup(s) on multiple pages acroos the site in a central location, declaratively.
Just an idea
Kristian M
Feb 22, 2008
Ryan Stuart says:
Sounds like a good idea to me. It goes without saying this should only be on opt...Sounds like a good idea to me. It goes without saying this should only be on option and not forced upon anyone. I think the default should be to just render the class error. But what you suggested in your comment Kristian would definitely make the new tag features a lot more powerful.
Jul 24, 2008
J says:
Here a quick solution for the smarter Grails tag problem: http://www.jtict.com/...Here a quick solution for the smarter Grails tag problem:
http://www.jtict.com/blog/shorter-grails-textfield/