Creating a UI Component in Struts 2

Problem

You have a form "element" that consists of several HTML actual elements. You'd like to create these using one Struts 2 UI tag, rather then write the HTML out everywhere it's needed.

Background

The Struts 2 UI tag library provide a component tag, which can be used to create your own "tags" without needing to dive into the JSP tag library API. Creating a tag using the Struts 2 component tag, also allows it to directly take advantage of the Struts 2 framework, such as OGNL support, and the existing Struts 2 UI tag themes.

Recipe

In this recipe we will creating an HTML control using the component tag that will display two input fields. This is a simple example, but it will show the process of creating a component, and tying it into the existing Struts 2 Xhtml theme. For our recipe we will pretend that we are collecting a US zip+4 zip code, using a separate input for the two components of the zip code. Using a component to do this will allow our double input "field" to coexist with the Xhtml theme and use the automatic layout provided by the theme. Unless we created a component to handle this situation, of needing two HTML input elements to be treated as one "component" by the Struts 2 tags, we would have to resort to using the Struts 2 Simple theme and writing our own HTML.

<s:textfield label="City" name="city" />
<s:textfield label="State" name="state" />
<tr>
	<td>Zip+4</td> <!-- Manually outputting our label -->
	<td>
		<s:textfield name="zip" theme="simple" />
		<s:textfield name="plus4" theme="simple" />
	</td>
</tr>

Although this is serviceable, it would be better if we could allow the Struts 2 tags to handle our layout. It simplifies form creation and allows uniform styling to be automatically applied. Also, should a change happen in how zip codes are collected, we would have to revisit every form that has this HTML construct on it, and change it. If we were to replace this with a component, all of our markup for zip+4 would be contained in one place in our code, and could be changed simply by changing our component template.

The Struts 2 UI Xhtml Theme

We will start with the standard Struts 2 Xhtml theme. To control the layout of the table elements that wrap our form elements the Xhtml theme uses two files, controlheader.ftl and controlfooter.ftl. All of the logic for the table elements, arrangement of labels, and presentation of field errors is located in these files. We don't want to re-create these so we will use them as the basis for our component.

The Xhtml Theme text.ftl Template

To create our component we will start with the text.ftl template from the Xhtml theme.

1: <#include "/${parameters.templateDir}/${parameters.theme}/controlheader.ftl" />
2: <#include "/${parameters.templateDir}/simple/text.ftl" />
3: <#include "/${parameters.templateDir}/xhtml/controlfooter.ftl" />

First let's examine this template: As you can see the theme template uses many common templates to create their output and to extend other themes. Throughout the Xhtml theme you will see it including template files from the simple theme to create the actual input element. This allows the Xhtml theme to concentrate on the layout of the form in the table, and the presentation of errors.

Our Component Template

We start with the text.ftl template and simply replace the second line with the content we want. In our case two textfield's. We use the existing Struts 2 textfield UI tag to do this.

<#include "/${parameters.templateDir}/${parameters.theme}/controlheader.ftl" />
<@s.textfield theme="simple" name="${parameters.zipName?default('')}" 
                 value="${parameters.zipValue?default('')}" /> + 
<@s.textfield theme="simple" name="${parameters.plus4Name?default('')}" 
                 value="${parameters.plus4Value?default('')}" />
<#include "/${parameters.templateDir}/xhtml/controlfooter.ftl" />

Using the existing Struts 2 textfield allows us to leverage the existing tags. This allows a markup to remain highly consistent. Accessing the information passed into our component is done using the parameters variable. Our component will take four values: Let's revisit our example from earlier and use our new tag:

    <s:textfield name="" label="City" />
    <s:textfield name="" label="State" />
    <s:component template="/components/zipplus4field.ftl" label="Zip+4">
        <s:param name="zipName" value="%{'zip'}" />
        <s:param name="zipValue" value="%{zip}" />
        <s:param name="plus4Name" value="%{'plus4'}" />
        <s:param name="plus4Value" value="%{plus4}" />
    </s:component>

All of the boilerplate HTML code is gone. Instead we are left with very clean Struts 2 tags.

Discussion

Using the Struts 2 UI tags and custom components you can encapsulate repetitive HTML patterns. Keeping your HTML mark up isolated in your component templates keeps it all in one place. Should you need to change it you will only have to do this in one place. Also, using UI components and extending the existing themes allows your HTML markup to participate in the Struts 2 themes, freeing you from laying out your forms in tables, or using other layout techniques. To see how it all fits together download the example project.