Search code examples
springjspspring-form

Spring forms + JSP: Binding the value of a <select> to a map<String, String> - what am I doing wrong


I'm using spring 3.0.5 and tomcat 7

What I'm doing:

I have created a table of select elements in JSP. Each select is associated with an id in my model, like this:

<form:form commandName="someStuff" method="post" id="peopleForm" onSubmit="return validate('${someStuff}');">

<%-- A bunch of other unrelated stuff here --%>
<table>
    <th>some other info</th>
    <th>please select a name</th> 
    <c:forEach var="thisThing" items="${allOfTheThings}">
        <tr>
        <td>some other info here</td>
        <td>
            <form:select id="name_for_thing_${thisThing.SomeId}" path = "tempNames['${thisThing.SomeId}']"  thisThingsId="${thisThing.SomeId}" class="thing_name_selector_class">
                <option value="Please Select One">Please Select One</option>
                <option value="John">John</option>
                <option value="Joe">Joe</option>
                <option value="Stephen">Stephen</option>
                <option value="Mary">Mary</option>
            </form:select >
        </td>
        </tr>
    </c:forEach>
</form:form>

and then in my domain object 'someStuff'

I define a map like:

private Map<String, String> tempNames;

public Map<String, String> getTempNames() {
    return tempNames;
}

public void setTempNames(Map<String, String> tempNames) {
    this.tempNames = tempNames;
}

The problem:

If I select values from the dropdown and submit this form, I can put a breakpoint in the controller and see that 'tempNames' has all the correct values in it like, that I can process and save - which is exactly what i'd expect - so the binding works one way...

However, if 'someStuff' already has values in it, those values are not bound to the dropdowns.

I've tried

Adding a 'value' attribute to the element itself like:

<form:select id="name_for_thing_${thisThing.SomeId}" path = "tempNames['${thisThing.SomeId}']" value="tempNames['${thisThing.SomeId}']" thisThingsId="${thisThing.SomeId}" class="thing_name_selector_class">

and also like this:

<form:select id="name_for_thing_${thisThing.SomeId}" path = "tempNames['${thisThing.SomeId}']" value="${tempNames[thisThing.SomeId]}" thisThingsId="${thisThing.SomeId}" class="thing_name_selector_class">

but that second one doesn't seem to even be showing up in the resulting HTML....


Solution

  • I've come across the same issue. Seems that you have to calculate option's selected flag by yourself:

    <form:select id="name_for_thing_${thisThing.SomeId}" path = "tempNames['${thisThing.SomeId}']"  thisThingsId="${thisThing.SomeId}" class="thing_name_selector_class">
            <option value="Please Select One">Please Select One</option>
        <c:choose>
            <c:when test="${tempNames['${thisThing.SomeId}'] == "John"}">
                <option value="John" selected="true">John</option>
            </c:when>
            <c:otherwise>
                <option value="John">John</option>
            </c:otherwise>
        </c:choose>
    
        ...
    </form:select >
    

    Please note that <option selected="${tempNames['${thisThing.SomeId}'] == "John"}"> won't work. Browser (at least Chrome) ignore the contents of selected attribute, the only thing that matters is presence/absense of the attribute itself: selected="false" still makes the option selected.