Iterating over nested objects in a Spring form
Spring 3 allows for wonderfully simply forms and automatic binding of form values back to the command object. However if your command object has further nested objects that you want to make editable from the form as well things get a little tricky. In that case you can’t just use a standard JSTL forEach loop as this will not allow you to build the path to the nested object correctly. The trick is to use the varStatus attribute to keep track of the index.
Sets and Lists
Assuming that your command object is called target the following will do just fine:
<ul> <c:forEach items="${target.nestedObjects}" varStatus="index"> <li> <form:input path="nestedObjects[${index.count - 1}].property" /> <form:errors path="nestedObjects[${index.count - 1}].property" cssClass="errors" /> </li> </c:forEach> </ul>
Keep in mind that the varStatus counter is one-based while most collections’ indices are zero-based; hence the “itemIndex.count – 1” expression.
Another way is to use the <spring:bind> tag. This will allow you to use standard HTML-Tags at the expense of some Spring form tricks such as checkboxes that are always submitted.
<ul> <c:forEach items="${target.nestedObjects}" varStatus="index"> <li> <spring:bind path="nestedObjects[${index.count - 1}].property" /> <input type="text" name="${status.expression}" value="${status.value}" /> <p class="errors">${status.errorMessages}</p> </li> </c:forEach> </ul>
Of course you can also mix and match both approaches as you see fit.
Maps
To iterate over a map the approach is slightly different:
<ul> <c:forEach items="${target.nestedMap}" varStatus="index"> <li> <form:input path="nestedObjects[${index.current.key}].property" /> <form:errors path="nestedObjects[${index.current.key}].property" cssClass="errors" /> </li> </c:forEach> </ul>As you can see the varStatus variable will be set to each respective map entry as they are iterated. Therefore “index.current.value” is also available if needed.
Tweet
Hi i’ve tried the Sets and Lists but when i submit the form, it says:
org.springframework.beans.InvalidPropertyException: Invalid property ‘userDetails.userExperiences[0]’ of bean class [com.myproject.contact.UI.form.EditProfileApplicant]: Illegal attempt to get property ‘userExperiences’ threw exception; nested exception is org.springframework.beans.InvalidPropertyException: Invalid property ‘userDetails.userExperiences[0]’ of bean class [com.myproject.contact.UI.form.EditProfileApplicant]: Cannot get element with index 0 from Set of size 0, accessed using property path ‘userExperiences[0]’
Please help.
Tonmoy,
it’s hard to say without seeing your code. It seems that userDetails.userExperiences is a Set, but an empty one, so of course no properties can be accessed.