Customizing the field widget of the Platform UI Grails plugin

Our team is working on a Grails plugin now, which will have UI based on Platform UI Grails plugin. Platform UI plugin allows you to easily configure Grails applications look using different page markups(themes). It provides a bunch of useful UI sets and allows the developers customize application look easily by creating own UI sets and themes.

Below I will show you an example of how to customize your UI easily using this plugin.

One of the Platform UI widgets you will use in your GSPs often is definitely the ui:field tag. Let’s have a look at how to use it:

<ui:field bean="${user}" name="enabled" type="checkbox" checked="checked"/>Code language: HTML, XML (xml)

The above will produce an input element and, in addition, all the functionality in it’s wrapper we may possibly want. It will produce input’s label, errors, that could be discovered after the field is validated and the help hints. Another really useful thing about this widget is that it allows us to put custom label/input/errors/help hints in it, using related tags: fieldInput, fieldLabel, fieldErrors, fieldHint. So, for example, if we write the following:

<ui:field name="${user}" name="enabled" type="checkbox" checked="checked">
    <ui:fieldLabel>Do you want this user to be enabled?</ui:fieldLabel>
</ui:field>Code language: HTML, XML (xml)

the generated label will be ignored, and the one, found in the fieldLabel tag body, will be used instead.

Ok, now, as we know about a lot of this widgets’ goodness, we might be curious to have a look at the produced output. The first thing you will notice is that the checkbox is not checked, even though we have set “checked” attribute when we called the widget. This happens because of the disadvantage of the default implementation of the template, rendered by ui:input tag, used in the field widget: when the input tag renders an input HTML element, it only renders a hardcoded set of the HTML attributes, leaving additional ones behind, which is obviously not good.

So now we should customize an _input.gsp template implementation: in our plugin/application /grails-app/view directory we should create the following folder structure: /grails-app/view/_ui/SomeCustomTheme and place our implementation of the _input.gsp there. Ok, so as we see from the input tag code snippet:

def args = [
    attrs:attrs, 
    // Some more arguments
]

out << renderUITemplate('input', args)Code language: JavaScript (javascript)

all attributes we passed is being passed to the template in the attrs map parameter. So what we gonna do, we gonna create our own tag that will take additional attributes and create proper HTML input element. The code for it will look like this:

def customAttrInput = { attrs ->

        def additionalAttrs = [:]

        // Removing attributes we want to set in the input template code 
        // from the additional attributes
        if (attrs.additionalAttrs) {
            ['type', 'class', 'value', 'id', 'name'].each { attrs.additionalAttrs.remove(it) }
            additionalAttrs = attrs.additionalAttrs
        }

        // Removing additional attributes from the whole attributes list.
        // We just don't want them to appear in the resulting HTML
        attrs.remove('additionalAttrs')

        out << "<input" + TagLibUtils.attrsToString(attrs)
            + TagLibUtils.attrsToString(additionalAttrs) + "/>"
}Code language: JavaScript (javascript)

And now, in the overriden _input.gsp, we should replace this

<input id="${id.encodeAsHTML()}" name="${name.encodeAsHTML()}"  
 class="${classes.encodeAsHTML()}" type="${type}"
 value="${value?.encodeAsHTML()}"/>Code language: JavaScript (javascript)

with the following:

<uix:customAttrInput id="${id.encodeAsHTML()}" name="${name.encodeAsHTML()}"  
 class="${classes.encodeAsHTML()}" type="${type}"
 value="${value?.encodeAsHTML()} additionalAttrs="${attrs}"/>Code language: JavaScript (javascript)

and here we go: now our field widget is supporting additional HTML attributes and we still use single line of code when adding new field to the GSP pages of our application/plugin.

Hope this will be kinda helpful for the developers who are starting to play with the Platform UI, so have fun!

Software Developer