Customizing the Field Widget of the Platform UI Grails Plugin

Our team is working on a Grails plugin now, which will have a UI based on the Platform UI Grails plugin. The platform UI plugin allows you to easily configure the look of Grails applications using different page markups(themes). It provides a bunch of useful UI sets and allows developers to customize the application’s look easily by creating their 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’ll use often in your GSPs is the <ui:field> tag. Let’s look at how to use it:

<ui:field bean="${user}" name="enabled" type="checkbox" checked="checked"/>

The above will produce an input element and, in addition, all the functionality in its wrapper that we may possibly want. It will produce the 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 labels/inputs/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>

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

Ok, now, as we know a lot about the goodness of these widgets, 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 the “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 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)

all attributes we passed are being passed to the template in the attrs map parameter. So what we’re gonna do we gonna create our own tag that will take additional attributes and create a 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) + "/>"
}

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

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

with the following:

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

and here we go: now our field widget is supporting additional HTML attributes, and we still use a single line of code when adding a 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