Recipe3.4.Using Indexed Properties on Forms


Recipe 3.4. Using Indexed Properties on Forms

Problem

You want to create a set of input fields on a form that corresponds to the indexed properties of a bean.

Solution

Use the indexed attribute on tags in the Struts html tag library to generate the property value:

<html:form action="TestOneAction"><p>   <logic:iterate name="MyForm" property="stringArray"                      index>     <br/>     <html:text property="stringArray" indexed="true"/> </logic:iterate> </html:form>

Discussion

As shown in Recipe 3.3, accessing indexed properties for display purposes is easy. However, using indexed properties in a form can be tricky. If the name of the generated input field is not formatted correctly, Struts can't populate the ActionForm when the HTML form is submitted. Struts populates the ActionForm with values from the HTTP request using the Jakarta Commons BeanUtils package. Specifically, the BeanUtils.populate( ) method loads the ActionForm from the HTTP request data sent when the form is submitted.

For indexed properties, BeanUtils.populate( ) uses the name of the request parameter to determine the proper setter method to call on the ActionForm. Table 3-3 illustrates how different form input field names are processed. The table shows the HTML tag, the corresponding HTTP request name/value pair, and the method that is called on the ActionForm when the request is processed.

Table 3-3. ActionForm population samples

HTML form input tag

Generated request pair

Resulting method call

<input type="text" name="bar">

bar=someValue

Form.setBar("someValue")

<input type="text" name="sna.fug">

sna.fug=blah

Form.getSna( ).setFug("blah");

<input type="text" name="baz[0]">

baz[0]=someValue

Form.setBaz(0,"firstVal");

<input type="text" name="glub[1].waf">

glub[1].waf=halb

Form.getGlub(1).setWaf("halb");

<input type="text" name="dog.leg[2]">

dog.leg[2]=lame

Form.getDog( ).setLeg(2, "lame");


Consider a form that allows a user to enter a list of favorite things such as colors and web sites. The ActionForm to hold this data contains a String property for the user's name, a String array representing the user's favorite colors, and a List of WebLink objects representing the user's favorite web sites. The WebLink class, shown in Example 3-5, defines a simple JavaBean with properties for the site name and URL.

Example 3-5. WebLink JavaBean
package com.oreilly.strutsckbk; public class WebLink {     public String getName( ) {         return name;     }     public void setName(String name) {         this.name = name;     }     public String getUrl( ) {         return url;     }     public void setUrl(String url) {         this.url = url;     }     private String url;     private String name; }

The form bean, FavoritesForm, containing properties for the user's name, favorite colors, and favorite links is shown in Example 3-6.

Example 3-6. FavoritesForm form bean
package com.oreilly.strutsckbk; import java.util.ArrayList; import java.util.List; import org.apache.struts.action.ActionForm; public final class FavoritesForm extends ActionForm  {     public FavoritesForm( ) {         webLinks = new ArrayList( );         for (int i=0; i<5; i++) webLinks.add(new WebLink( ));          colors = new String[3];     }         public String getName( ) {         return name;     }     public void setName(String name) {         this.name = name;     }     public String getColor(int index) {         return colors[index];     }     public void setColor(int index, String color) {         colors[index] = color;     }     public String[] getColor( ) {         return colors;     }     public List getWebLinks( ) {         return webLinks;     }     public WebLink getWebLink(int index) {         return (WebLink)webLinks.get(index);     }     public void setWebLink(int index, WebLink webLink) {         webLinks.set(index, webLink);     }          public void reset( ) {         webLinks.clear( );         colors = new String[3];     }          private List webLinks;     private String name;             private String[] colors;     }

Now you can create a JSP page (favorites.jsp) that allows a user to input corresponding data on a form, as shown in Example 3-7.

Example 3-7. FavoritesForm JSP
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %> <%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %> <%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %> <%@ taglib uri="http://java.sun.com/jstl/core" prefix="c" %> <html:html locale="true"> <head> <title><bean:message key="index.title"/></title> <html:base/> </head> <body bgcolor="white"> <h2>Favorites Poll</h2> <html:form action="/admin/ViewFavorites">     <p>         What is your name:         <br/><html:text property="name"/>     </p>     <p>         What are your three favorite colors:         <br/><html:text property="color[0]"/>         <br/><html:text property="color[1]"/>         <br/><html:text property="color[2]"/>     </p>    <p>       What are your favorite links?       <table>          <tr>             <th>Name</th>             <th>URL</th>          </tr>          <tr>             <td><html:text property="webLink[0].name"/></td>             <td><html:text property="webLink[0].url"/></td>          </tr>       </table>    </p>     <html:submit/>     <html:reset/> </html:form> </body> </html:html>

Since the index values in Example 3-7 are hardcoded and not dynamic, the html:text tag property values are easily constructed, so the generated HTML tags have the appropriate name attribute values. However, suppose you wanted to use the logic:iterate tag to generate the repeated input fields. To do this for the color property, you might be tempted to try some JSP code like this:

What are your three favorite colors:   <logic:iterate name="FavoritesForm" >     <br/><html:text property="color" indexed="true"/>   </logic:iterate>

This will not generate the needed HTML markup. The indexed attribute applies an index (i.e., [n]) to the value specified for the name attribute of the particular Struts html tag (in this case, html:text). If you were to deploy a JSP using the snippet above, the generated HTML would look something like the following:

What are your three favorite colors: <br/><input type="text" name="org.apache.struts.taglib.html. BEAN[0].color" value="[Ljava.lang.String;@5f1ba8"> <br/><input type="text" name="org.apache.struts.taglib.html. BEAN[1].color" value="[Ljava.lang.String;@5f1ba8"> <br/><input type="text" name="org.apache.struts.taglib.html. BEAN[2].color" value="[Ljava.lang.String;@5f1ba8">

The index is not applied to the value for the property. Instead, the value is applied to the internal Struts name for the form bean. Additionally, the value attribute contains the results of calling toString( ) on the array, and not a specific element in the array.

What this means in the long run is that the indexed attribute is useful when you need to set a nested simple property of an indexed property that is a complex objecte.g., a JavaBean. You can generate the input fields for a non-nested property in a logic:iterate tag, but you must resort to scriptlet to generate the array index:

What are your three favorite colors:   <logic:iterate name="FavoritesForm"  index>     <br/><html:text property='<%="color["+ctr+"]"%>'/>   </logic:iterate>

Suppose you wanted to use the logic:iterate tag to generate input fields for the favorite links (the WebLink objects). In this case, the indexed attribute will do exactly what you want:

What are your favorite links? <table>   <tr>      <th>Name</th>      <th>URL</th>   </tr>   <logic:iterate  name="FavoritesForm" property="webLinks">     <tr>       <td><html:text name="webLink" property="name" indexed="true"/></td>       <td><html:text name="webLink" property="url" indexed="true"/></td>     </tr>   </logic:iterate> <table>

Using the indexed attribute with the html tag library can be confusing. This confusion generally stems from the name attribute's new importance. In most cases, when using the html tags, the name attribute can be left off as the value will be based on the form-bean that is declared for the action mapping. However, when using the indexed attribute, the name attribute refers to the nested indexed property of the corresponding ActionForm.

Going back to the problem with the color property, you have alternatives other than using scriptlet. You can use the Struts html-el tags or JSTL. Both of these alternatives essentially do the same thing as the scriptlet, but they do so using EL (expression language). The cleanest approach utilizes the html-el tags:

What are your three favorite colors:   <logic:iterate name="FavoritesForm"  index>     <br/><html-el:text property='color[${ctr}]>'/>   </logic:iterate>

If you prefer JSTL, you can generate the required input tag directly instead of using the Struts html tags:

What are your three favorite colors: <logic:iterate  name="FavoritesForm" property="color" index>    <br/><input type="text" name="color[<c:out value='${ctr}'/>]"              
value="<c:out value='${FavoritesForm.color[ctr]}'/>"/>
</logic:iterate>

This JSTL version is about as ugly as the original version using scriptlet. In addition, since neither the Struts html:text nor html-el:text tag is used, the HTML input tag's value attribute must be explicitly coded. If you were to use the Struts html:text tag, the value would be set automatically.

The Struts-EL tags extend the Struts base tags but are not part of the Struts core. Bug fixes and new features for the base Struts tag take time to find their way to the Struts-EL tags.


See Also

Recipe 3.3 discusses techniques to use when displaying values from indexed properties outside of a form. Recipe 3.5 discusses how to use indexed properties in a JSTL c:forEach loop.

The BeanUtils package of the Jakarta Commons project defines how the indexed properties are resolved. The package description provides additional details and can be found at http://jakarta.apache.org/commons/beanutils/api/org/apache/commons/beanutils/package-summary.html#package_description.



    Jakarta Struts Cookbook
    Jakarta Struts Cookbook
    ISBN: 059600771X
    EAN: 2147483647
    Year: 2005
    Pages: 200

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net