Maxlength HTML attribute for domain objects

With Grails domain classes, constraints can be specified - including the maximum size of a String. For example:

class Book {
String title

static def constraints = {
title(maxSize:20)
}
}

When using 'grails generate-all' to create scaffolding, you'll notice that create.gsp and add.gsp hardcode the maxlength attribute:
<input type="text" maxlength="20" id="title" name="title"
value="${fieldValue(bean:book,field:'title')}"/>

It is possible to directly reference the constraint, meaning that the maxlength attribute is not hardcoded - and thus only defined once (in the domain object):
<input type="text" maxlength="${Book.constraints.title.getMaxSize()}"
id="title" name="title"
value="${fieldValue(bean:book,field:'title')}"/>

In fact, we can go even further and create a tag where we pass in the object itself, and the name (which matches the property name) and we can dynamically generate the maxlength and value attributes.

So when editing a book with the title set to 'my new book', the following code:
<jttext:textField object="${book}" name="title"/>

produces the following HTML:
<input type="text" name="title" maxlength="20" value="my new book"
id="title" />

The tag library to produce this is as follows:

import org.codehaus.groovy.grails.plugins.web.taglib.FormTagLib

class TextTagLib extends FormTagLib {
static namespace = "jttext"

def textField = {attrs ->
attrs.type = "text"
attrs.tagName = "textField"

def object = attrs.remove('object')
def maxlength = object.constraints."${attrs.name}".getMaxSize()
if(maxlength) {
attrs.put('maxlength', maxlength)
}
attrs.put('value', fieldValue(bean:object,field:attrs.name))

def result = field(attrs)
if (result) {
out << result
}
}
}

It makes sense to me that the tag does all of the work - it reduces duplication and makes the code more readable.

What do you think?

Popular posts from this blog

Using the Crystal Reports Java API to generate PDF

No Scope registered for scope request

Using Selenium WebDriver to select JSF/PrimeFaces selectOneMenu options