Collect and save submitted values of multiple dynamic HTML inputs back in servlet

Given this simplified model:

public class Item {
    private Long id;
    private String foo;
    private String bar;
    // ...
}

Here’s how you can do it provided ${items} is List<Item>:

<c:forEach items="${items}" var="item">
    <tr>
        <td>
            <input type="hidden" name="id" value="${item.id}" />
            <input name="foo_${item.id}" value="${fn:escapeXml(item.foo)}" />
        </td>  
        <td>
            <input name="bar_${item.id}" value="${fn:escapeXml(item.bar)}" />
        </td>
    </tr>
</c:forEach>

(note the importance of fn:escapeXml() as XSS attack prevention)

So, basically, you need to set the item’s unique identifier as a hidden input field in each row as shown in above snippet:

<input type="hidden" name="id" value="${item.id}" />

And you should in turn use this id as suffix of name of all input fields in the same row such as:

<input name="foo_${item.id}" ... />

In the servlet, you can collect all values of <input type="hidden" name="id" ...> from all rows by request.getParameterValues(). Just loop over it and then grab the individual inputs by id.

for (String id : request.getParameterValues("id")) {
    String foo = request.getParameter("foo_" + id);
    String bar = request.getParameter("bar_" + id);
    // ...
}

You can also do this all without that id and grab all inputs by name as an array like so name="foo" and request.getParameterValues("foo"), but the ordering of request parameters is not under your control. HTML forms will send it in order, but the enduser can easily manipulate the order.

No need for JavaScript mess here.

See also:

Leave a Comment