Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

This how-to will cover how to use both numeric indexed properties and string-indexed or mapped properties. Indexed properties are hard to define, but easy to show by example. Imagine we wanted to edit information about a bug on a page. We might create a form with fields like "bug.name", "bug.description", "bug.priority" etc. Now imagine we want to edit multiple bugs at once, on the same page. We could write a form (and an ActionBean) with an awful lot of properties, like "bug1.name", "bug2.name", etc. but that's way too much work. So instead we use a notation that is understood by Stripes (and lots of other tools), and call our form fields bug[0].name and bug[1].name and so on.

To accomplish this there are two aspects to consider: How to generate the names of the fields on the form and how to code an ActionBean that can receive them. Both are actually quite simple.

...

The following is an example fragment of a JSP using indexed properties (it is a simplified version of a page from the Bugzooky Sample Application):

Code Block
xml
languagexml
title"Using indexed properties in a JSP"
<stripes:form action="/bugzooky/EditPeople.action"> 
    <table class="display"> 
        <tr> 
            <th>ID</th> 
            <th>Username</th> 
            <th>First Name</th> 
            <th>Last Name</th> 
            <th>Email</th> 
        </tr> 
        <c:forEach items="${personManager.allPeople}" var="person" varStatus="loop"> 
            <tr> 
                <td> 
                    ${person.id} 
                    <stripes:hidden name="people[${loop.index}].id" value="${person.id}"/> 
                </td> 
                <td>
                    <stripes:text name="people[${loop.index}].username" value="${person.username}"/>
                </td> 
                <td>
                    <stripes:text name="people[${loop.index}].firstName" value="${person.firstName}"/>
                </td> 
                <td>
                    <stripes:text name="people[${loop.index}].lastName" value="${person.lastName}"/>
                </td> 
                <td>
                    <stripes:text name="people[${loop.index}].email" value="${person.email}"/>
                </td> 
            </tr> 
            <c:set var="newIndex" value="${loop.index + 1}" scope="page"/>
        </c:forEach> 
        <%-- And now, an empty row, to allow the adding of new users. --%> 
        <tr> 
            <td></td> 
            <td></td> 
            <td>
                <stripes:text name="people[${newIndex}].username"/>
            </td> 
            <td>
                <stripes:text name="people[${newIndex}].firstName"/>
            </td> 
            <td>
                <stripes:text name="people[${newIndex}].lastName"/>
            </td> 
            <td>
                <stripes:text name="people[${newIndex}].email"/>
            </td> 
        </tr> 
    </table> 

    <div class="buttons">
        <stripes:submit name="Save" value="Save Changes"/>
    </div> 
</stripes:form> 

...

This is an area where Stripes really shines. The relevant piece of the ActionBean which corresponds to the above form is:

Code Block
languagejava
title"Using indexed properties in an ActionBean"
private List<Person> people; 

@ValidateNestedProperties ({ 
    @Validate(field="username", required=true, minlength=3, maxlength=15), 
    @Validate(field="firstName", required=true, maxlength=25), 
    @Validate(field="lastName", required=true, maxlength=25), 
    @Validate(field="email", mask="[\\w\\.]+@[\\w\\.]+\\.\\w+") 
}) 
public List<Person> getPeople() { return people; } 
public void setPeople(List<Person> people) { this.people = people; } 

...

For example, imagine we had a page to edit a Person and that the Person has a property 'pets' which is a List of Pet objects, and each Pet has a List of Nicknames. To validate these properties we write the validations without any indexing - just as if they were regular properties:

Code Block
languagejava
titleSpecifying validations of indexed properties
@ValidateNestedProperties({ 
    @Validate(field="phoneNumber", required=true), 
    @Validate(field="pets.age", required=true, maxvalue=100), 
    @Validate(field="pets.nicknames.name", required=true, maxlength=50), 
}) 
private Person person; 

...

The following example shows how you might use indexed properties with a Map to capture a large set of options or parameters with as little effort as possible. In this case the Map key is the String name of the parameter and the Map value is the numerical value of the parameter.

Code Block
xml
languagexml
titleMap/Indexed properties with String keys in the JSP
<stripes:form ... > 
    ... 
    <table> 
        <c:forEach items="${toolParams}" var="toolParam"> 
            <tr> 
                <td>${toolParam.name}:</td> 
                <td><stripes:text name="toolParameters['${toolParam.name}']"/></td> 
            </tr> 
        </c:forEach> 
    </table> 
    ... 
</stripes:form> 

The relevant section of the ActionBean:

Code Block
languagejava
titleMap/Indexed properties with String keys in the ActionBean
private Map<String,Double> toolParameters; 

public Map<String,Double> getToolParameters() { return toolParameters; } 
public void setToolParameters(Map<String,Double> toolParameters) { 
    this.toolParameters = toolParameters; 
} 

...

The last point is worth explaining in more detail. What is means is that you can have ActionBean properties that looks like this:

Code Block
languagejava
public Map<Date,List<Appointment>> getAppoinments() { return appointments; } 
public void setAppoinments(Map<Date,List<Appointment>> appointments) { 
    this.appointments = appointments; 
} 

and have input fields that look like this:

Code Block
xml
languagexml
Note: <stripes:text name="appointments[${date}][${idx}].note"/>