What I wonder is if there's a easier/better way to handle dynamic forms (adding form items to the dom via js) when using SpringMVC and Spring forms?
Imaging having an Invoice object that have many LineItems.
public class Invocie {
private List LineItems;
public Invoice() {
lineItems = ListUtils.lazyList(new ArrayList<LineItem>(), FactoryUtils.instantiateFactory(LineItem.class));
}
}
To show the items belonging to an Invoice I currently use
<forEach items="${invoice.lineItems}" varStatus="i">
<form:input path="lineItems[${i.index}].productName" />
</c:forEach>
To add LineItems I have some js that calculates the new index and adds that to the DOM. When deleting a LineItem i currently have to renumber all the indexes and that's the part I'd like to avoid, is it possible?
I've implemented a tutorial that might help you solve this using jQuery on the client side and Springs AutoPopulating list for you form backing objects.
http://eggsylife.co.uk/2009/11/30/spring-forms-dynamic-lists-and-ajax/
EDIT Link from Webarchive https://web.archive.org/web/20160729163958/http://eggsylife.co.uk/2009/11/30/spring-forms-dynamic-lists-and-ajax/
You could use the following
public class InvoiceController extends SimpleFormController {
protected void initBinder(HttpServletRequest request, ServletRequetDataBinder binder) throws Exception {
binder.registerCustomEditor(List.class, "lineItems", new CustomCollectionEditor(List.class)() {
protected Object convertElement(Object lineItem) {
LineItem li = (LineItem) lineItem;
// StringUtils is a jakarta Commons lang static class
return (StringUtils.isBlank(li.getProductName())) ? null : li;
}
});
}
}
Then in onBind method, you remove null references according to:
protected void onBind(HttpServletRequest request, Object command, BindException bindException) throws Exception {
Invoice invoice = (Invoice) command;
invoice.getLineItems().removeAll(Collections.singletonList(null));
}
Regards,
I've found that also decorating with a GrowthList is necessary to avoid some errors when adding/setting items in JSP. (Also created a custom SpringList impl. that basically does the double decoration.)
lineItems = GrowthList.decorate(ListUtils.lazyList(new ArrayList<LineItem>(), FactoryUtils.instantiateFactory(LineItem.class)));
I agree. The problem is certainly removing items.
What you can do is use the spring marker syntax in the html. So if you remove an item (at index 2 for example) from the list using javascript, you would then mark that index with:
<input type="hidden" name="_lineItems[2]">
Then when the form is submitted spring will see the marker and put in an empty item (based on the lazylist factory) for lineItems2 instead of ignoring it.
I've been struggling with this problem today and figured out some solution described here.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With