Thursday
Oct 23, 2008
10:23 am
Spring Binding with Lists and A Form Gotcha
Suppose we have an application that uses two kinds of beans: a Subscriber bean and a Dependent bean. We have a form that is used to edit the Subscriber and each Subscriber may have zero or more Dependents who are also editable. All the fields for Subscriber have been bound with Spring <form:form> tags. However, the dependents are a list of beans. What we want is dynamic binding with a List of objects. Fortunately, iterating through the objects is made easier with the use of JSTL. The only tricky part is making sure the right form elements are bound to the right dependents.
In order to accomplish that, the code looks something like this:
<form:form commandName = "myCommandObject" method = "post" cssClass = "aForm" id = "aSearchForm">
<h1>The subscriber</h1>
<p>
<form:input path = "subscriberObject.firstName" size = "15"/>
</p>
<p>
<form:input path = "subscriberObject.lastName" size = "20"/>
</p>
<p>
<form:radiobutton path = "subscriberObject.gender" value = "F"/>
Female
<form:radiobutton path = "subscriberObject.gender" value = "M"/>
Male
</p>
<p>
<label>
<form:checkbox path = "subscriberObject.currentSubscriber" value = "Y"/>
Current subscriber
</label>
</p>
<c:choose>
<c:when test = "${empty myCommandObject.subscriberObject.dependentObjects}">
<p>No dependents listed</p>
</c:when>
<c:otherwise>
<c:forEach items = "${myCommandObject.subscriberObject.dependentObjects}" var = "dependent" varStatus = "dependentRow">
<form:input path = "subscriberObject.dependentObject[${dependentRow.index}].firstName" size = "15"/>
<form:input path = "subscriberObject.dependentObject[${dependentRow.index}].lastName" size = "20"/>
<p>
<form:radiobutton path = "subscriberObject.dependentObject[${dependentRow.index}].gender" value = "F"/>
Female
<form:radiobutton path = "subscriberObject.dependentObject[${dependentRow.index}].gender" value = "M"/>
Male
</p>
<p>
<label>
<form:checkbox path = "subscriberObject.dependentObject[${dependentRow.index}].currentSubscriber" value = "Y"/>
Current subscriber
</label>
</p>
</c:forEach>
</c:otherwise>
</c:choose>
<input class = "buttonStyle" value = "submit" type = "submit"/>
</form:form>Now for the gotcha. It turns out that the gender value for dependents may come back as either “F” or “Female” and “M” or “Male”. As near as I can tell, Spring MVC determines whether the radio button is selected based on whether the bound value matches the radio button value. In the form above, if subscriberObject.dependentObject[${dependentRow.index}].gender is set to “Female”, neither radio button will be selected.
The following (old-school) binding is therefore necessary:
<spring:bind path="eligibilityCommand.subscriberObject.dependentObject[ ${dependentRow.index} ].gender">
<input type="radio" name="<c:out value="${status.expression}"/>" value="F"<c:if test="${status.value=='F'||status.value=='Female'}"> checked="checked"</c:if> /> Female
<input type="radio" name="<c:out value="${status.expression}"/>" value="M"<c:if test="${status.value=='M'||status.value=='Male'}"> checked="checked"</c:if> /> Male
</spring:bind>The subscriber object in the form only contains a List of dependents since the form is not dynamic (the user cannot add or remove dependents on the fly). If that were the case, it would have to use LazyList. Matt Fleming has this post and this one about dynamic list binding.