The problem
The Binding among the inputs
and the List
in the Spring model is done through an index in the name of the input
. For example:
<form:input path="products[${i.index}].quantidade" id="quantidade${i.index}" />
<form:input path="products[${i.index}].total" id="total${i.index}" />
Your Javascript logic is probably simply removing the elements from form
, e. g.:
function removeProduct(index) {
var myForm= document.getElementById('form');
var quantidade = document.getElementById('product[' + index + '].quantidade');
var total = document.getElementById('product[' + index + '].total');
myForm.removeChild(quantidade);
myForm.removeChild(total);
}
As a consequence, after removing any item other than the last one from the list, the inputs
in his form
get messy, e.g.:
<input type="text" name="products[0].quantidade" id="quantidade1" value="10" />
<input type="text" name="products[0].total" id="total1" value="10000" />
<input type="text" name="products[3].quantidade" id="quantidade4" value="8" />
<input type="text" name="products[3].total" id="total4" value="800" />
When you submit this form
the Spring
popularize the list by skipping the elements in the indexes 1
and 2
.
Solutions
Reindexar the names of inputs
with client-side Javascript (for example, after each removal or before sending the form
). This is the most "clean" solution, but it can get complicated, especially when you have nested lists within lists. If you go that way I suggest you structure your Markup in order to facilitate the change of name of inputs of a common product (e.g., by grouping the sets of inputs of a product with a div
).
Do not remove the inputs. You can use any logic instead of removing the inputs from the DOM. For example, you can hide the inputs
and include a input hidden
to indicate that the attribute has been removed. This is an easy solution, but it wastes a bit of bandwidth and memory as you well noted.
<form:hidden path="products[${status.index}].remove" />
- Ajax: You can do operations dynamically in the background every time the user clicks to remove. This is a good solution thinking about keeping the atomic operations (each item in the list is updated individually), but it is important that you understand the trade-offs in terms of usability. By making an Ajax call every time someone clicks to remove from the Javascript side you are anticipating the removal operation to before the
submit
(what may or may not be desirable).
- Clear the list before using it on the server side: It’s ugly more works.
- Use a self-organizing collection. I marked an article in the references that implements a
ShrinkableLazyList
References:
Spring MVC and form Binding : how to remove an item from a List ?
Dynamic Forms, Lazylist and Transparent items Removal
Excellent response!
– utluiz
Thank you very much to all the answers, they don’t know how much it helped. And let’s continue like this, learning and growing.
– Giancarlo Abel Giulian