Recipe8.5.Validating an Indexed Property


Recipe 8.5. Validating an Indexed Property

Problem

You want to validate a field that is a nested property of an object in an array or Collection.

Solution

Set the indexedListProperty attribute for the field element to the name of the property that returns the array or Collection. The value of the property attribute will be interpreted as the name of a nested property of an element within the Collection. If you're using Struts 1.2, you can reference the indexed property in a test for a validwhen rule. Example 8-5 shows a complete form element from validation.xml for a form containing the array property "orders."

Example 8-5. Validations for an indexed list property (partial)
<form name="IndexedListForm">     <field property="partNumber" indexedListProperty="orders"             depends="minlength">         <arg position="0" key="prompt.partNumber"/>         <arg position="1" key="${var:minlength}" resource="false"/>         <var>             <var-name>minlength</var-name>             <var-value>5</var-value>         </var>     </field>     <field property="quantity" indexedListProperty="orders"             depends="intRange,validwhen">         <arg position="0" key="prompt.quantity"/>         <arg position="1" key="${var:min}" resource="false"/>         <arg position="2" key="${var:max}" resource="false"/>         <msg name="validwhen" key="error.quantity.invalid"/>         <var>             <var-name>min</var-name>             <var-value>5</var-value>         </var>         <var>             <var-name>max</var-name>             <var-value>20</var-value>         </var>         <var>             <var-name>test</var-name>             <var-value>                 (((orders[].partNumber != null) and (*this* != null)) or                   ((orders[].partNumber == null) and (*this* == null)))              </var-value>         </var>     </field> </form>

Discussion

The indexedListProperty permits you to define one set of validation rules applied to repeated fields on a form. Say you have a JSP page like the one shown in Example 8-6 (indexed_list_test2.jsp) that allows a user to place orders for specific part numbers and quantities.

Example 8-6. JSP for rendering indexed properties
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %> <%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %> <%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %> <html> <head>   <title>Struts Cookbook Chapter 8 : Indexed List Validation</title> </head> <body bgcolor="white"> <h2>Struts Cookbook Chapter 8 :  Indexed List Validation</h2>   <html:form action="/ProcessIndexedListTest2">     <table>         <tr>             <th><bean:message key="prompt.partNumber"/></th>             <th><bean:message key="prompt.quantity"/></th>         </tr>           <logic:iterate name="IndexedListForm" property="orders"                            index>             <tr>                 <td>                     <html:text name="orders" property="partNumber"                             indexed="true"/><br />&nbsp;                     <html:messages                               property='<%="orders["+ndx+"].partNumber"%>'>                          <font color="red"><bean:write name="error"/></font>                     </html:messages>                 </td>                 <td>                     <html:text name="orders" property="quantity"                             indexed="true"/><br />&nbsp;                     <html:messages                               property='<%="orders["+ndx+"].quantity"%>'>                          <font color="red"><bean:write name="error"/></font>                     </html:messages>                 </td>             </tr>         </logic:iterate>     </table>     <html:submit/>   </html:form> </body> </html>

The rendered HTML form for the JSP in Example 8-6 is shown in Example 8-7.

Example 8-7. Generated HTML for indexed properties
<html> <head>   <title>Struts Cookbook Chapter 8 : Indexed List Validation</title> </head> <body bgcolor="white"> <h2>Struts Cookbook Chapter 8 :  Indexed List Validation</h2>   <form name="IndexedListForm" method="post"        action="/jsc-ch08/ProcessIndexedListTest2.do">     <table>         <tr>             <th>Part number</th>             <th>Quantity</th>         </tr>                       <tr>                 <td>                     <input type="text" name="orders[0].partNumber" value="">                     <br />&nbsp;                 </td>                 <td>                     <input type="text" name="orders[0].quantity" value="">                     <br />&nbsp;                 </td>             </tr>             <tr>                 <td>                     <input type="text" name="orders[1].partNumber" value="">                     <br />&nbsp;                 </td>                 <td>                     <input type="text" name="orders[1].quantity" value="">                     <br />&nbsp;                 </td>             </tr>             <tr>                 <td>                     <input type="text" name="orders[2].partNumber" value="">                     <br />&nbsp;                 </td>                 <td>                     <input type="text" name="orders[2].quantity" value="">                     <br />&nbsp;                 </td>             </tr>             <tr>                 <td>                     <input type="text" name="orders[3].partNumber" value="">                     <br />&nbsp;                 </td>                 <td>                     <input type="text" name="orders[3].quantity" value="">                     <br />&nbsp;                 </td>             </tr>             <tr>                 <td>                     <input type="text" name="orders[4].partNumber" value="">                     <br />&nbsp;                 </td>                 <td>                     <input type="text" name="orders[4].quantity" value="">                     <br />&nbsp;                 </td>             </tr>     </table>     <input type="submit" value="Submit">   </form> </body> </html>

By setting property="partNumber" and indexedListProperty="orders", you define a validation rule that will be evaluated for each indexed property submitted. In the Solution, each part number is checked using the minlength rule.

<field property="partNumber" indexedListProperty="orders"         depends="minlength">     <arg position="0" key="prompt.partNumber"/>     <arg position="1" key="${var:minlength}" resource="false"/>     <var>         <var-name>minlength</var-name>         <var-value>7</var-value>     </var> </field>

The rule only applies if the property being validated has a non-blank value. Users don't have to enter five part numbers if they don't want to. If you wanted to force the users to enter a value for every part number field, you would specify the required rule as well.

In the Solution, the quantity is validated. The intRange rule validates that an entered quantity is between 5 and 20. This field uses the validwhen rule with a rather verbose test.

<var>     <var-name>test</var-name>     <var-value>         (((orders[].partNumber != null) and (*this* != null)) or           ((orders[].partNumber == null) and (*this* == null)))      </var-value> </var>

The test ensures that if a quantity is entered, a part number must also be entered. Likewise, if a part number isn't entered, the quantity should be blank. The operand, orders[].partNumber, allows you to refer to a nested property of an indexed object. The [] notation tells the Validator that the expression applies to each object in the array. You can refer to a specific index in the property attribute value or a validwhen expression. If you wanted to require that a part number and quantity were entered for the first row, use the following:

<field property="orders[0].partNumber"         depends="required">     <arg position="0" key="prompt.partNumber"/> </field>

A common problem when validating multiple rows is that one error message is generated for each rule type for a field. In the Solution, for example, the quantity range validation is generated for the first failing property. You can see the practical results of this behavior in Figure 8-1. Though both quantity fields are invalid, the error is generated for the first quantity field.

Figure 8-1. Indexed list JSP with errors


Unfortunately, this is a quirk of the Validator when using indexed properties. When the Validator encounters the first error for a particular field, it won't continue to check additional indices of the same field. If this presents a problem, you may want to go back to displaying the errors at the top of the page or take the tried and true method and hand code the validate( ) method to do what you want.

See Also

For additional details on using indexed properties in forms see Recipe 3.4. The validwhen rule is discussed in Recipe 8.4.

For custom rendering of error messages, look at Recipe 9.6.

You'll find a number of interesting discussions on the struts-user mailing list; search on "indexedListProperty" and "array validation."



    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