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.
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.
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.
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.
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.
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.
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.
| Attachment | Size |
|---|---|
| struts2component.tar_.gz | 8.98 KB |
Hi,
I am trying to create a custombuttonbar component which can house one or more nested custombutton components. I have created three ftls,
my code looks something like this... (skipping the unnecessary details)
<s:component template="custombuttonbar.ftl">
<s:component template="custombutton.ftl"/>
</s:component>
but with this, the ftls are firing in a weird order. custombutton.ftl fires first. then custombuttonbar.ftl and the custombuttonbar-close.ftl does not fire at all! So i have temporarily written this in the ugly form
<s:component template="custombuttonbar.ftl"/> <s:component template="custombutton.ftl"/> <s:component template="custombuttonbar-close.ftl"/>
Hope someone can help me solve this problem..
Hi,
I had exactly the same need as you. I found nothing consistent on nested content for Struts UI tags. It's a shame. So I used the "param" tag to embed the nested content, like this :
button-bar.ftl :
<div class="button-bar">
<div class="buttonBarContainer">
${parameters.body?if_exists?html}
</div>
</div>
example.jsp :
<s:component template="button-bar.ftl">
<s:param name="body">
<s:submit name="create" type="button" label="commons.action.create" />
</s:param>
</s:component>
may be this way can solve your problem.
${parameters.body?string}
Hi,
I have followed you're example in an attempt to have two datetimepicker(s) side by side, I get everything to work except that using s:param in my jsp does not seem to pass the parameters to the ftl file. I have tried you're example on my environment it does not work either.
Do you have any ideas
environment
-----------
jboss 4.2.2
struts 2.0.9
java 5.11ish
Cheers Alan.
Hi Mark,
I.m trying to do the same sort of thing using the struts datetimepicker tag. However I receive a freemarker error,
s.datetimepicker not found
Is it possible to do this using any struts tag? I am missing something simple?
Regards,
Alan.
If you are using Struts 2.1.X, you must have the struts2-dojo-plugin-2.1.X.jar in your library. Then, you must put in your page the following:
> > So you need to include ' taglib uri="/struts-dojo-tags" prefix="sx" '
> > and ' sx:head/ '
> >
> > and call sx:datetimepicker .../
> >
> > Michaël
And that's it! I had the same problem, and this guy Michael helped me out.
Cheers bro
--Alfredo
I download struts2component.tar.gz file, but I have different to open it. How can I open or unzip example project?
Thanks
Eric
Try changing the name to struts2component.tar.gz instead of struts2component.tar_.gz. For some reason when I upload the file through my CMS it adds the underscore. Removing the underscore might allow your file type bindings to match.
How do i increase the column width
Hi Mark,
I really liked your theme. What I am trying to do is I am trying to create column which extends across multiple rows. Is that possible using the qxhtml theme.