Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

better way for dynamic forms with Spring?

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?

like image 311
NA. Avatar asked May 20 '09 21:05

NA.


4 Answers

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/

like image 74
eggsy84 Avatar answered Nov 19 '22 05:11

eggsy84


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,

like image 32
Arthur Ronald Avatar answered Nov 19 '22 06:11

Arthur Ronald


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.

like image 1
case nelson Avatar answered Nov 19 '22 05:11

case nelson


I've been struggling with this problem today and figured out some solution described here.

like image 1
Lukasz Frankowski Avatar answered Nov 19 '22 04:11

Lukasz Frankowski