 | Level: Intermediate Danilo Gurovich (dan@gurovich.com), Principal Engineer, Earthlink Inc.
25 Oct 2005 Struts Recipes co-author Danilo Gurovich
picks up where George Franciscus left off with an easy-to-follow Struts
recipe for creating dynamically selected checkboxes.
In user interface design, the checkbox group isn't as popular as its
cousin, the multi-line selectbox. They both basically do the same thing; that is, they choose a collection of options mapped to a single name
attribute. When used in groups, checkboxes actually perform the
same function as the multi-line selectboxes, but they take up a little more
screen real estate. This can be beneficial when you want the user to be
able to view all the choices before selecting one or several of
them.
While the multi-line selectbox typically provides a better look and feel
when the choices are limited, a group of checkboxes is the better choice
for any enterprise application where selection boxes must be rendered
dynamically and contain preselection functionality. Fortunately,
creating a group of dynamic checkboxes is easy to do with the Struts
framework.
In this article, I show you a simple recipe using the Struts <html:multibox/> and <logic:iterate/> tags to present a number of
items in an application's view layer, in this case a Java™ Server Page (JSP).
I'll start by using checkbox elements to show a simple String[] array of mountain peaks in the Himalayas.
Then, I'll create another String[] array of
selectedMountains to represent the
checkboxes that have been selected. The preselection of the checkboxes
will occur at the intersection of the two arrays. If the selectedMountains initial array is empty, all
checkboxes will initially appear unchecked.
See Download for the complete
example source code. You should have everything you need to follow
along. See Resources if you need to download
the Struts framework.
Creating dynamic checkboxes
The recipe for creating dynamic checkboxes consists of three major pieces:
- A form bean that holds a
String[] array
of checkboxes and a String[] array of
selected checkboxes
- A JSP with a form that shows the checkboxes in the state you
require
- A simple
Action class to go from the form page to the
display page
Note that the "Himalayas" example is very simple. The fields used to
populate a checkbox should come from a more sophisticated model, such as one that could identify the user and choose the fields to show and then
precheck any that a business object may deem necessary. I've used a
simple model to better demonstrate Struts's UI functionality. The code samples use the JSP scripting language where appropriate for clarity.
Step 1. Create the form bean
I'll start by creating a Struts form bean that contains the
information needed to populate the checkboxes. Note that TestForm.java in Listing 1 includes getters and setters
for the two example String[] array
variables. The array mountains represents
all of the checkboxes for the example, and the array selectedMountains represents the checked elements
preselected to show in the browser.
In addition to representing the initially selected checkboxes, selectedMountains also represents checkboxes
checked by the user when the form is processed. (It represents only
the final checked elements.) When the page is requested, the checkboxes
are displayed. As I iterate over them, any checkbox element that
matches selectedMountains is checked.
Listing 1 shows the complete code for TestForm.java:
Listing 1. TestForm.java
package com.strutsrecipes;
import javax.servlet.http.HttpServletRequest;
import org.apache.struts.action.ActionError;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionMapping;
public final class CheckboxTestForm
extends ActionForm {
// Instance Variables
/*Mountains "pre-selected"...*/
private String[]
selectedMountains
=
{"Everest","K2","Lhotse"};
/*the ten tallest Mountains to iterate through*/
private String[]
mountains
=
{"Everest","K2","Kangchenjunga","Lhotse",
"Makalu","Kangchenjunga South",
"Lhotse Middle","Kangchenjunga West",
"Lhotse Shar","Cho Oyu"};
/*Getter for selectedMountains*/
public String[] getSelectedMountains() {
return this.selectedMountains;
}
/*Setter for selectedMountains*/
public void setSelectedMountains(String[] selectedMountains) {
this.selectedMountains = selectedMountains;
}
/*Getter for the mountains*/
public String[] getMountains() {
return this.mountains;
}
/*Setter for the mountains*/
public void setMountains(String[] mountains) {
this.mountains = mountains;
}
}
|
 |
Step 2. Write the JSP code
Next, I write the JSP code for the page that propagates
TestForm.java's information to the view layer. When
writing this code, it is essential to import the corresponding Struts
taglibs onto the JSP. The JSP code in Listing 2 is for a simple
form that displays checkboxes with the appropriate ones checked:
Listing 2. The JSP with the form
<%@taglib uri="http://jakarta.apache.org/struts/tags-html" prefix="html"%>
<%@taglib uri="http://jakarta.apache.org/struts/tags-bean" prefix="bean"%>
<%@taglib uri="http://jakarta.apache.org/struts/tags-logic" prefix="logic"%>
<%-- html code, etc... -->
<html:form
action="/FormAction"
name="testForm"
type="com.strutsrecipes.CheckboxTestForm">
<h4><bean:message key="testForm.instruction"/></h4>
<logic:iterate name="testForm"
property="mountains"
id="mountain">
<%-- create the checkbox and selected attribute -->
<html:multibox property="selectedMountains">
<bean:write name="mountain"/>
</html:multibox>
<%-- create the label, note that "br" tag will format it vertically -->
<bean:write name="mountain"/><br/>
</logic:iterate>
<br/>
<html:submit/><html:reset/>
</html:form>
<%-- some more html code, etc... -->
|
Notice that I'm using the Struts <bean:message/> tag for text, the <html:multibox/> for the HTML checkboxes, and
the <logic:iterate/> tag to iterate
through arrays and create everything. My form bean is instantiated on
the JSP by the <html:form/> tag.
My next step is to iterate through the mountains field in the <logic:iterate/> tag. In so doing, I create a
variable ( mountain) to populate the checkbox
and give it a label using the <bean:write/> tag. To create the selected attribute in the checkbox, I'll again use
the <logic:iterate/> and <html:multibox/> tags. The property attribute in the <html:multibox/> tag is populated by the
selectedMountains field. The selectBox is checked when selectedMountains equals mountain.
Step 3. Write the Action class
My final step is to write the Action
class. Not much is happening in Listing 3 compared to the others. All
I do is get the String[] array of
selectedMountains and make it available to
the page:
Listing 3. The Action for the form
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
/**
* A simple Action for Checkbox test.
*
* @author Danilo Gurovich
*/
public final class CheckboxTestAction
extends Action {
// -------------------------- OTHER METHODS --------------------------
/**
* The execute method
*
* @param mapping ActionMapping
* @param form CheckboxTestForm
* @param request HttpServletRequest
* @param response HttpServletRespons
* @return success to the confirmation page
* @throws ServletException not thrown, but could be!
* @throws Exception ditto.
*/
public ActionForward execute(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws ServletException, Exception {
// Extract attributes needed
String[] selectedMountains =
((CheckboxTestForm) form).getSelectedMountains()
;
System.out.println("htmlString RETURNED*\n" +
selectedMountains.toString());
//Save the htmlString in the session for later...
HttpSession session = request.getSession();
session.setAttribute(CheckboxConstants.MOUNTAINS, selectedMountains);
return (mapping.findForward("success"));
}
}
|
 |
Scaling the Himalayas
And with that, I'm finished with the "heavy lifting" and I'm almost
ready to show off my fine work! The user may now submit the JSP form and
review the results in the corresponding page referenced by the
Action class. The code snippet in Listing 4
shows the list of boxes checked by the user in the form of a simple JSP:
Listing 4. The results of the checked boxes
<%@taglib uri="http://jakarta.apache.org/struts/tags-html" prefix="html"%>
<%@taglib uri="http://jakarta.apache.org/struts/tags-bean" prefix="bean"%>
<%@taglib uri="http://jakarta.apache.org/struts/tags-logic" prefix="logic"%>
<%-- html code, etc... -->
<logic:iterate id="mountain" property="mountains" name="testForm">
<bean:write name="mountain"/><br/>
</logic:iterate>
<hr size=5 color="black"/>
<%-- some more html code, etc... -->
|
How the recipe works
The key to this recipe is the way the fields in the form bean are propagated to the page. A look at the pertinent JSP code helps clarify this. Once the form bean is instantiated:
<html:form action="/FormAction"
name="testForm"
type=" com.strutsrecipes.CheckboxTestForm">
|
the next step is to create a checkbox for every mountain in the mountains variable of the Java class. To do this, I
have to iterate through the String[] array
like this:
<logic:iterate id="mountain"
property="mountains"
name="testForm">
|
With the <logic:iterate> tag, I call
the getMountains() method in the testForm bean. It iterates through this array
and return each value as a mountain[] pageContext()-level String array variable (that is,
id="mountain") that I have named.
Here you can see what affects the actual <html:multibox/> tag and how it will be
displayed:
<html:multibox property="selectedMountains">
<bean:write name="mountain"/>
</html:multibox>
<bean:write name="mountain"/><br/>
|
Notice that the property attribute is
filled with selectedMountains, which is my
checked variable. When this value corresponds with the <html:multibox/> value (that is, the <bean:write/> inside the multibox tags), it
appears as checked when the form is rendered. If the user checks or
unchecks the form, the new selectedMountains
value(s) is sent to the Action class for
processing. The second <bean:write/>
tag in this iteration creates the label that the tag uses,
followed by a <br/> tag to make the
view show the tags in a long column.
Extending the recipe
You can extend the dynamic checkbox recipe to create different labels
for your checkboxes by using the Struts LabelValueBean class instead of a simple String[] array. You start by adding the LabelValueBeans to a java.util.List. You then iterate through the
list and extract the LabelValueBeans labels
and values to their appropriate places. This slightly more complex
recipe achieves the same results as the dynamic checkbox recipe,
but with results more applicable to real-world UI design. Listing 5 shows the extended
dynamic checkbox recipe:
Listing 5. Adding labels to dynamic checkboxes
<logic:iterate id="mountainlb"
property="mountainslb"
name="testForm">
<bean:define id="mountainbean"
name="mountainlb
"type="org.apache.struts.util.LabelValueBean"/>
<html:multibox property="selectedMountains">
<bean:write name="mountainbean"
property="value"/>
</html:multibox>
<bean:write name="mountainbean"
property="label"/><br/>
</logic:iterate>
|
Note that the big change here is using <bean:define/> to create the LabelValueBean as it iterates. You then use <bean:write/> to write out the properties of
each mountainbean (that is, the getLabel() and getValue() methods of the org.apache.struts.util.LabelValueBean class).
In conclusion
Struts provides excellent support for dynamically rendering and
preselecting checkboxes. This recipe was one of the reasons that I
co-authored Struts Recipes -- at the time I had found lots of
theory and server-side information related to the Struts framework,
but UI programming was mostly ignored, or at best glossed over. After
searching high and low for a recipe to create checkboxes using Struts, I
gave up and wrote my own. By combining various pieces, I was able to
build a dynamic checkbox system that suited me.
You'll notice that the code sample is set up to be useful as a test
bed for different UI widgets and layouts ideas. In fact, I used it for
most of the UI examples in the book, just tweaking the Action class and my model to fit the needs of the
recipe. I've also used it in development to test different ideas without
spending too much time coding up something inside the application I was
working on.
Download | Description | Name | Size | Download method |
|---|
| Sample code | j-sr3-source.zip | 3249 KB | HTTP |
|---|
Resources Learn
- "Struts-
Velocity integration" (George Franciscus, developerWorks, September
2005): The Velocity Template Engine is a fast, flexible alternative to
Java ServerPages in Struts.
- "Integrating Struts, Tiles, and JavaServer Faces" (Srikanth
Shenoy and Nithin Mallya, developerWorks, September 2003): Harness the
front-end power of JavaServer Faces, the formatting strength of Tiles,
and the flexibility of the Struts controller tier.
- Struts Recipes (George
Franciscus and Danilo Gurovich; Manning, 2004): A popular compendium of
Struts recipes and best practices.
- Struts In Action (Ted Husted,
Cedric Dumoulin, George Franciscus, David Winterfeldt; Manning, 2002): A
comprehensive resource for professional Struts developers.
- The Java technology
zone: Find articles about every aspect of Java programming.
Get products and technologies
Discuss
About the author  | 
|  | Danilo Gurovich is an application architect who has designed and
implemented Struts-based applications for high-traffic commerce, EAI
monitoring and controlling, and business process management. He is the
co-author of Struts
Recipes with George Franciscus. |
Rate this page
|  |