October 05, 2009

Spring MVC - Dynamic list binding and validating the input data


It took quiet some time to figure out how to display a dynamic list of data on screen and get user input information back. We also had to perform validation on this dynamic list input data and display error message on the corresponding row.  
Here is the simple example to achieve the above requirement.

Consider that you need to display Parent and list of child information on a screen and get the Age and Sex information of each child. Also you need to show error message on the screen if the user has not entered the age or sex information.

1) Form bean

public class MotherFormBean{  
   private String name;  
   private List<Child> children;  
   public MotherFormBean() {  
     children= LazyList.decorate(new ArrayList(),  
       FactoryUtils.instantiateFactory(Child.class));  
   }  
 }  
 public class Child{  
   private String name;  
   private String age;  
   private String sex;  
 }  

Instead of initializing the List as normal ArrayList, use the LazyList class (Commons-collection package). This is to avoid "IndexOutOfBoundException" when the data is submitted back to the controller.

2) JSP

<form:form action="${formAction}" name="childrenDetails">  
 <table><thead>  
  <tr>  
   <th><b>Name</b></th>  
   <th><b>Sex</b></th>  
   <th><b>Age</b></th>  
  </tr>  
  </thead>   
  <tbody>   
   <c:foreach items="${command.children}" var="child" varStatus="loop">   
    <tr>   
     <td><c:out value="${child.name}"></c:out>  
       <form:hidden path="children[${loop.index}].name"/>   
     </td>  
     <td><form:select path="children[${loop.index}].sex">  
        <option value="">--Please Select--</option>  
        <option value="M">Male</option>  
        <option value="F">Female</option>   
       </form:select>  
     </td>  
     <td><form:input path="children[${loop.index}].age"/></td>   
    </tr>  
   </c:foreach>   
  </tbody>   
  </table>  
 </form:form>  

This code will print all the children names and show input fields for Age and Sex field.

3) Validator Class

When the List data is submitted back, Spring constructs the data back to the Form bean with help of the LazyList collection. Validation and raising error on these fields is very simple.

 public class MotherBeanValidator implements org.springframework.validation.Validator {  
 .......   
   public void validate(Object target, Errors errors) {  
     MotherFormBean bean = (MotherFormBean) target;  
     List<Child> children = bean.getChildren();  
     for (int i = 0; i < children.size(); i++) {  
       if (StringUtils.isEmpty(children.get(i).getSex()))   
        errors.rejectValue("children[" + i + "].sex", "select.sex");  
       if (StringUtils.isEmpty(children.get(i).getAge()))   
        errors.rejectValue("children[" + i + "].age", "select.age");  
     }  
   }  
 }  

JSP Changes:
Include <form:errors> tag after the sex and age input fields.
eg.)
 <form:errors path="children[${loop.index}].sex"/>   
Hope this helps you in displaying the Collection data using Spring MVC and validating it.

Thanks to Matt Flemings blog for shedding some light on the LazyList.

13 comments:

  1. Hi.
    This is for showing the dynamic list of child items. can you please help me writing a function that adds the item into the list using spring binding ?


    Thanks
    Ahsan

    ReplyDelete
  2. Hi,

    I have the same issue. I need to add elements to the list dynamically using javascript. How can I bind these elements. Currently I am getting IndexOutOfbound exception when I add the elements.

    Please help.

    ReplyDelete
  3. Hi,

    As mentioned in this post, use LazyList.decorate() method to initialize your list in the Model. This will avoid throwing IndexOutOfBoundException.

    Regards,
    Venky

    ReplyDelete
  4. Used LazyList. It works great with Adding new objects.

    It is not recognizing if the objects are REMOVED from the list.

    Is there any work around? or am I missing anything?

    ReplyDelete
  5. sorry, I am not clear with my above question. My UI should be able to ADD and DELETE items.

    LazyList is working great with ADD. It is binding dynamically. But when I DELETE, it is not removing from the LazyList.

    What can I do to remove the items from list?

    ReplyDelete
  6. LazyList will only initialize the objects in the list with the "index" you provide from your UI.

    Consider you had 3 elements in the list and you deleted 2nd element (index=1) on your UI. When you submit the form, size of the LazyList will still be 3 but the second element in the List will be NULL.
    So you can handle the delete operation in the code by doing a NULL check.

    ReplyDelete
    Replies
    1. This is really HelpFul..I got stucked with how to validate a list!!
      But your post helped me on that..
      Thanks a lot!!

      Delete
  7. I want to add text boxes that depend upon the click on the type of radio button. In spring how can I achieve this? I tried with java script and added successfully but the problem is then How will I bind my data so that I can see validation and submit the data to backend? Please help. Thanks -Ankit

    ReplyDelete
    Replies
    1. http://outbottle.com/spring-3-mvc-adding-objects-to-a-list-element-on-the-fly-at-form-submit-generic-method/

      Delete
  8. http://outbottle.com/spring-3-mvc-adding-objects-to-a-list-element-on-the-fly-at-form-submit-generic-method/

    refer the above site

    ReplyDelete
  9. Thanks mate, this worked a treat!!!

    ReplyDelete
  10. Thanks friend !! [${loop.index}] really worked ....

    ReplyDelete
  11. Lazy List is showing error!

    ReplyDelete