Announcement Announcement Module
Collapse
No announcement yet.
Example for Spring MVC with dynamic Check box list Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Example for Spring MVC with dynamic Check box list

    Since there are still many ones ask about how to use Spring MVC to handle a dynamic Check box list form, I just created a very simple example, so that it may be used as a reference.

    Class MyCategory
    PHP Code:
    package com.dlu.bus;

    import java.util.ArrayList;
    import java.util.List;

    /**
     * @author derekxlu
     *
     */
    public class MyCategory {
        
        private List 
    items;


        
    /**
         * @return the items
         */
        
    public List getItems() {
            return 
    items;
        }


        
    /**
         * @param items the items to set
         */
        
    public void setItems(List items) {
            
    this.items items;
        }

        
    /**
         * 
         * @param numOfItems
         * @return
         */
        
    public static MyCategory createSampleData(int numOfItems){
            
    ArrayList newitems = new ArrayList();
            for (
    int i=0i<numOfItemsi++) {
                
    MyItem item = new MyItem();
                
    item.setId(123);
                
    item.setDescription("Item No. " i);
                
    newitems.add(item);
                if (
    i%2==0)
                    
    item.setSelected(true);
            }
            
    MyCategory category = new MyCategory();
            
    category.setItems(newitems);
            
            return 
    category;
            
        }

    class MyItem
    PHP Code:
    package com.dlu.bus;

    /**
     * @author derekxlu
     *
     */
    public class MyItem {
        private 
    int id;
        private 
    String description;
        private 
    boolean selected;
        
        
    /**
         * @return the id
         */
        
    public int getId() {
            return 
    id;
        }
        
        
    /**
         * @param id the id to set
         */
        
    public void setId(int id) {
            
    this.id id;
        }
        
        
    /**
         * @return the description
         */
        
    public String getDescription() {
            return 
    description;
        }
        
        
    /**
         * @param description the description to set
         */
        
    public void setDescription(String description) {
            
    this.description description;
        }
        
        
    /**
         * @return the selected
         */
        
    public boolean isSelected() {
            return 
    selected;
        }
        
        
    /**
         * @param selected the selected to set
         */
        
    public void setSelected(boolean selected) {
            
    this.selected selected;
        }


    Class MyCheckboxListFormController
    PHP Code:
    package com.dlu.web;

    import java.util.HashMap;
    import java.util.Map;

    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;

    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    import org.springframework.validation.BindException;
    import org.springframework.web.servlet.ModelAndView;
    import org.springframework.web.servlet.mvc.SimpleFormController;

    import com.dlu.bus.MyCategory;

    public class 
    MyCheckboxListFormController extends SimpleFormController {

        
    /** Logger for this class and subclasses */
        
    protected final Log logger LogFactory.getLog(getClass());

        public 
    MyCheckboxListFormController() {
            
    setCommandName("category");
            
    setCommandClass(MyCategory.class);
          }

        
    /*
         * (non-Javadoc)
         * @see org.springframework.web.servlet.mvc.AbstractFormController#formBackingObject(javax.servlet.http.HttpServletRequest)
         */
          
    protected Object formBackingObject(HttpServletRequest request)
            
    throws Exception {
            
    MyCategory category MyCategory.createSampleData(7);
            
            return 
    category;
          }

          
    /*
           * (non-Javadoc)
           * @see org.springframework.web.servlet.mvc.SimpleFormController#onSubmit(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, java.lang.Object, org.springframework.validation.BindException)
           */
          
    public ModelAndView onSubmit(
            
    HttpServletRequest request,
            
    HttpServletResponse response,
            
    Object command,
            
    BindException errorsthrows Exception {

            
    MyCategory category = (MyCategorycommand;
            
    //hey it's fully populated

            
    Map myModel = new HashMap();
            
    myModel.put("category"category);

            return new 
    ModelAndView(getSuccessView(), myModel);
          }



    checkboxlist.jsp
    PHP Code:
    <%@ include file="/WEB-INF/jsp/include.jsp" %>
    <%@ 
    taglib prefix="spring" uri="/spring" %>

    <
    html>
    <
    head><title>Check Box List</title></head>
    <
    body>
    <
    form method="post">
    <
    table border="1">
      <
    c:forEach items="${category.items}var="myitem" varStatus="myitemstatus">
      <
    tr>
         <
    spring:bind path="category.items[${myitemstatus.index}].selected"
            <
    td><c:out value="${myitem.id}"/> </td>
            <
    td><c:out value="${myitem.description}"/> </td>
            <
    td>
            <
    input type="hidden" name="_<c:out value="${status.expression}"/>">
            <
    input type="checkbox" name="<c:out value="${status.expression}"/>" value="true"
                
    <c:if test="${status.value}">checked</c:if>/>
            </
    td>
         </
    spring:bind>
         </
    tr>
       </
    c:forEach>
       </
    table>
      <
    br>
      <
    br><br>
      <
    input type="submit" align="middle" value="Get Result">
    </
    form>
    </
    body>
    </
    html
    checkboxresult.jsp
    PHP Code:
    <%@ include file="/WEB-INF/jsp/include.jsp" %>
    <%@ 
    taglib prefix="spring" uri="/spring" %>

    <
    html>
    <
    head><title>Check Box List Result</title></head>
    <
    body>
    <
    c:forEach items="${category.items}var="myitem">
      <
    c:out value="${myitem.id}"/> <i> <c:out value="${myitem.description}"/></i> <c:if test="${myitem.selected}"><i> <c:out value="selected"/></i></c:if><br><br>
    </
    c:forEach>
    <
    a href="<c:url value="checkboxlist.htm"/>">Play Again</a>
    </
    body>
    </
    html
    myapp-servlet.xml
    PHP Code:
    ......

        <
    bean id="myCheckboxListForm" class="com.dlu.web.MyCheckboxListFormController">
            <
    property name="sessionForm"><value>true</value></property>
            <
    property name="commandName"><value>category</value></property>
            <
    property name="commandClass"><value>com.dlu.bus.MyCategory</value></property>
            <
    property name="formView"><value>checkboxlist</value></property>
            <
    property name="successView"><value>checkboxresult</value></property>
        </
    bean>

    ......

        <
    bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
            <
    property name="mappings">
                <
    props>
                    <
    prop key="/checkboxlist.htm">myCheckboxListForm</prop>
                </
    props>
            </
    property>
        </
    bean>
        
        <
    bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
            <
    property name="viewClass"><value>org.springframework.web.servlet.view.JstlView</value></property>
            <
    property name="prefix"><value>/WEB-INF/jsp/</value></property>
            <
    property name="suffix"><value>.jsp</value></property>
    </
    bean
    include.jsp
    PHP Code:
    <%@ page session="false"%>

    <%@ 
    taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
    <%@ 
    taglib prefix="fmt" uri="http://java.sun.com/jstl/fmt" %> 
    Last edited by derekxlu; Dec 3rd, 2007, 05:25 PM.

  • #2
    1. Use form tags instead of the plain bind tags.
    2. The implementation of onSubmit(..) seems to be superfluous.

    Joerg

    Comment


    • #3
      dynamic check box using form tags

      Well, points are taken.

      I created a new checkboxlist.jsp with form tag as following
      checkboxlist.jsp
      PHP Code:
      <%@ include file="/WEB-INF/jsp/include.jsp" %>

      <
      html>
      <
      head><title>Check Box List</title></head>
      <
      body>
      <
      form:form method="post" commandName="category">
        <
      table border="1">

          <
      c:forEach items="${category.items}var="myitem" varStatus="status">
            <
      tr>
              <
      td><c:out value="${myitem.id}"/> </td>
              <
      td><c:out value="${myitem.description}"/> </td>
              <
      td>
              <
      form:checkbox path="items[${status.index}].selected"/>
              </
      td>
            </
      tr>
          </
      c:forEach>
        </
      table>
        <
      br><br><br>
        <
      input type="submit" align="middle" value="Get Result">
      </
      form:form>
      </
      body>
      </
      html
      The onSubmit(...) implementation was to show where the value can be manipulated. It can be simply removed, but in order for reader to get a clear picture, I created a simplified onSubmit(…) implementation as following (by doing nothing but for comment purpose)
      PHP Code:
            /*
             * (non-Javadoc)
             * @see org.springframework.web.servlet.mvc.SimpleFormController#onSubmit(java.lang.Object, org.springframework.validation.BindException)
             */
            
      protected ModelAndView onSubmit(Object commandBindException errorsthrows Exception {
                
      //command holds the populated Category instance
                
      return super.onSubmit(commanderrors);
              } 
      To use the new jsp, please update include.jsp as following
      PHP Code:
      <%@ page session="false"%>

      <%@ 
      taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
      <%@ 
      taglib prefix="fmt" uri="http://java.sun.com/jstl/fmt" %> 
      <%@ 
      taglib prefix="form" uri="http://www.springframework.org/tags/form" %> 
      Last edited by derekxlu; Dec 7th, 2007, 09:33 PM.

      Comment


      • #4
        Originally posted by derekxlu View Post
        Well, points are taken.

        I created a new checkboxlist.jsp with form tag as following
        checkboxlist.jsp
        PHP Code:
        <%@ include file="/WEB-INF/jsp/include.jsp" %>

        <
        html>
        <
        head><title>Check Box List</title></head>
        <
        body>
        <
        form:form method="post" commandName="category">
          <
        table border="1">

            <
        c:forEach items="${category.items}var="myitem" varStatus="status">
              <
        tr>
                <
        td><c:out value="${myitem.id}"/> </td>
                <
        td><c:out value="${myitem.description}"/> </td>
                <
        td>
                <
        form:checkbox path="items[${status.index}].selected"/>
                </
        td>
              </
        tr>
            </
        c:forEach>
          </
        table>
          <
        br><br><br>
          <
        input type="submit" align="middle" value="Get Result">
        </
        form:form>
        </
        body>
        </
        html
        The onSubmit(...) implementation was to show where the value can be manipulated. It can be simply removed, but in order for reader to get a clear picture, I created a simplified onSubmit(…) implementation as following (by doing nothing but for comment purpose)
        PHP Code:
              /*
               * (non-Javadoc)
               * @see org.springframework.web.servlet.mvc.SimpleFormController#onSubmit(java.lang.Object, org.springframework.validation.BindException)
               */
              
        protected ModelAndView onSubmit(Object commandBindException errorsthrows Exception {
                  
        //command holds the populated Category instance
                  
        return super.onSubmit(commanderrors);
                } 
        To use the new jsp, please update include.jsp as following
        PHP Code:
        <%@ page session="false"%>

        <%@ 
        taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
        <%@ 
        taglib prefix="fmt" uri="http://java.sun.com/jstl/fmt" %> 
        <%@ 
        taglib prefix="form" uri="http://www.springframework.org/tags/form" %> 
        Hi,

        I tried this example. However at MyCategory class I found all items of MyItem are with "false" for "selected" even one of the checkbox was selected. ?

        Wondering if we should define items as array instead of List because The source of the page showed checkbox has name="items[0].selected" defined.

        Jane

        Comment


        • #5
          Jane,

          Both examples works fine. As for using Array instead of List, it won't make difference, you may try following MyCategory with Array, the result are the same ( I ran it and it worked fine). I think there might be something else wrong with the environment that you tried the example.

          Thanks.

          Derek

          PHP Code:

          package com
          .dlu.bus;

          import java.util.ArrayList;

          /**
           * @author derekxlu
           *
           */
          public class MyCategory {
              
              private 
          MyItem[] items;


              
          /**
               * @return the items
               */
              
          public MyItem[] getItems() {
                  return 
          items;
              }


              
          /**
               * @param items the items to set
               */
              
          public void setItems(MyItem[] items) {
                  
          this.items items;
              }

              
          /**
               * 
               * @param numOfItems
               * @return
               */
              
          public static MyCategory createSampleData(int numOfItems){
                  
          ArrayList newitems = new ArrayList();
                  for (
          int i=0i<numOfItemsi++) {
                      
          MyItem item = new MyItem();
                      
          item.setId(123);
                      
          item.setDescription("Array Item No. " i);
                      
          newitems.add(item);
                      if (
          i%2==0)
                          
          item.setSelected(true);
                  }
                  
          MyCategory category = new MyCategory();
                  
          MyItem[] itemArray = (MyItem[])newitems.toArray(new MyItem[newitems.size()]);

                  
          category.setItems(itemArray);
                  
                  return 
          category;
                  
              }

          Comment


          • #6
            Originally posted by derekxlu View Post
            Jane,

            Both examples works fine. As for using Array instead of List, it won't make difference, you may try following MyCategory with Array, the result are the same ( I ran it and it worked fine). I think there might be something else wrong with the environment that you tried the example.

            Thanks.

            Derek

            PHP Code:

            package com
            .dlu.bus;

            import java.util.ArrayList;

            /**
             * @author derekxlu
             *
             */
            public class MyCategory {
                
                private 
            MyItem[] items;


                
            /**
                 * @return the items
                 */
                
            public MyItem[] getItems() {
                    return 
            items;
                }


                
            /**
                 * @param items the items to set
                 */
                
            public void setItems(MyItem[] items) {
                    
            this.items items;
                }

                
            /**
                 * 
                 * @param numOfItems
                 * @return
                 */
                
            public static MyCategory createSampleData(int numOfItems){
                    
            ArrayList newitems = new ArrayList();
                    for (
            int i=0i<numOfItemsi++) {
                        
            MyItem item = new MyItem();
                        
            item.setId(123);
                        
            item.setDescription("Array Item No. " i);
                        
            newitems.add(item);
                        if (
            i%2==0)
                            
            item.setSelected(true);
                    }
                    
            MyCategory category = new MyCategory();
                    
            MyItem[] itemArray = (MyItem[])newitems.toArray(new MyItem[newitems.size()]);

                    
            category.setItems(itemArray);
                    
                    return 
            category;
                    
                }

            Thanks Derek. Array makes no difference with List. The thing is strange - after I initialize the items to be true at creatSampleData it seemed working better. Some of the checkbox showed selected true and some false but in an opposite logic though - selected checkbox shows false. Anyway I changed initializing items back to false at creatSampleData. It worked. Don't know what made the magic.

            Comment


            • #7
              dynamic input text list

              Hi Derek,

              I am trying to make dynamic input text work as dynamic check box. I have <form:input path="items[${status.index}].description}"/>. But I got error:

              Invalid property 'items[0].description}' is not readable or has an invalid getter method: Does the re
              turn type of the getter match the parameter type of the setter?

              Can this dynamic input text list be implemented as the dynamic check box list?

              Thanks.

              Originally posted by derekxlu View Post
              Jane,

              Both examples works fine. As for using Array instead of List, it won't make difference, you may try following MyCategory with Array, the result are the same ( I ran it and it worked fine). I think there might be something else wrong with the environment that you tried the example.

              Thanks.

              Derek

              PHP Code:

              package com
              .dlu.bus;

              import java.util.ArrayList;

              /**
               * @author derekxlu
               *
               */
              public class MyCategory {
                  
                  private 
              MyItem[] items;


                  
              /**
                   * @return the items
                   */
                  
              public MyItem[] getItems() {
                      return 
              items;
                  }


                  
              /**
                   * @param items the items to set
                   */
                  
              public void setItems(MyItem[] items) {
                      
              this.items items;
                  }

                  
              /**
                   * 
                   * @param numOfItems
                   * @return
                   */
                  
              public static MyCategory createSampleData(int numOfItems){
                      
              ArrayList newitems = new ArrayList();
                      for (
              int i=0i<numOfItemsi++) {
                          
              MyItem item = new MyItem();
                          
              item.setId(123);
                          
              item.setDescription("Array Item No. " i);
                          
              newitems.add(item);
                          if (
              i%2==0)
                              
              item.setSelected(true);
                      }
                      
              MyCategory category = new MyCategory();
                      
              MyItem[] itemArray = (MyItem[])newitems.toArray(new MyItem[newitems.size()]);

                      
              category.setItems(itemArray);
                      
                      return 
              category;
                      
                  }

              Originally posted by jane View Post
              Thanks Derek. Array makes no difference with List. The thing is strange - after I initialize the items to be true at creatSampleData it seemed working better. Some of the checkbox showed selected true and some false but in an opposite logic though - selected checkbox shows false. Anyway I changed initializing items back to false at creatSampleData. It worked. Don't know what made the magic.

              Comment


              • #8
                Hi Jane,

                Sorry, just saw your post moment ago. The dynamic input works. You have a typo in your change. the correct change should be as following:

                <td><form:input path="items[${status.index}].description"/> </td>

                Notice that you have an extra '}" after the description.

                Hope this will help.

                Derek

                Originally posted by jane View Post
                Hi Derek,

                I am trying to make dynamic input text work as dynamic check box. I have <form:input path="items[${status.index}].description}"/>. But I got error:

                Invalid property 'items[0].description}' is not readable or has an invalid getter method: Does the re
                turn type of the getter match the parameter type of the setter?

                Can this dynamic input text list be implemented as the dynamic check box list?

                Thanks.

                Comment


                • #9
                  Thanks a lot derekxlu.

                  Comment


                  • #10
                    Thank you derekxlu

                    I was trying to solve this checkbox problem for weeks. I couldn't find any solution for it and finally I found your post. It is actually very helpfull.

                    thank you very very much derekxlu.
                    you are great!!!!

                    Comment


                    • #11
                      Example for Spring MVC with dynamic Check box list - doesn't work

                      Hello,
                      I'd just like to know your oppinion. I tried to solve problem with dynamic checkbox list few years ago when trying to get into JSF. I didn't make it.
                      I am really new in Spring MVC, so maybe there is a better solution than
                      I propose... I don't know.

                      Why do I think that this example doesn't work? It works fine only
                      for session form. The problem is when the command object is created
                      for every request. Usually the data for the command object are
                      delivered from the database, which might be a problem. As a user
                      may spend even 10 minutes on the form page, it is likely that
                      the data in the database could be changed during this interval.
                      That can cause a problem. Let say that we have 10 items on the page. User selects second and third item and submits the form which means that he wants to delete these items. What happens ? You create a list in formBackingObject() method with 10 records and later, within the binding phase, Spring selected second and third item as selected and then in onSubmit() method you can iterate over the collection and delete items that have selected flag set. This is fine - assuming the items are in the same order.

                      But imagine what happens when somebody else deletes, let say, first row from the table before user submits the form. Then your collection, that is created in formBackingObject() has only 9 items. Spring marks second and third items as selected and you will delete them later. The problem is that now second and third items are different items than were before submiting the form. So basicly you are not going to delete the records the user selected, but different records instead... which is bad.

                      This is exactly what I hate about web apps. I found one solution which is not spring-clear, but it works fine.
                      Simply don't let spring set the flag of items. Insert your own checkbox

                      <form:form command="category">
                      <c:foreach var="item" items="${category.items}" varStatus="loop">
                      <input name="ids" type="checkbox" value="${item.id}" <c:if test="${item.selected}">CHECKED</c:if>/>

                      When next request comes, create full collection in normal way - do not set the selected flag.
                      Then, let saz in onBind() method, you can obtain ids from the request as array of long values ... iterate over this array and for every id find an item in the list that has the same id and mark it as selected... ufff I hope it is clear.

                      Could be something like this (Writting by heart - so ignore syntax errors :-))

                      MyForm form = (MyForm) command;
                      String[] ids = request.getParameterValues("ids");
                      if (ids != null) {
                      for (String id : ids) {
                      for (Item item : form.getItems()) {
                      if (item.getItemId() == Long.parse(id).longValue()) {
                      item.setSelected(true);
                      break;
                      }
                      }
                      }
                      }

                      I hope its clear... There is even better way how to do it better way, but
                      it would be difficult to explain ... Let me know if somebody is interested.

                      So what do you say? Did anybody solve similar problem?
                      Thanks.

                      Comment


                      • #12
                        Hi,

                        I am dynamically creating a list of checkboxes via enums. All works well, after I submit, I receive the a List of the values that were selected. But I was also interested in receiving a List of the values that weren't selected. I could make things simple by looping over the array of enum values and see if it is in the list (or not) and set the selected indicator myself. But that seems a little overkill to me

                        I have the following code:
                        Command class:
                        Code:
                        ... //This is a list of enums.
                        private List<Check> checks = new ArrayList<Check>();
                        ...
                        In my jsp page:
                        Code:
                        ...
                        <c:forEach items="${checks}" var="check" varStatus="i">
                        	<tr>
                        		<td><form:checkbox path="checks" value="${check}"/></td><td><c:out value="${i.index}" /></td><td><c:out value="${check.label}" /></td><td><c:out value="${check.type.label}" /></td><td><c:out value="${check.recurring}" /></td>
                        	</tr>
                        </c:forEach>
                        ...
                        This works really great, but what I want is to replace the List of Checks with a List of CampaignChecks.

                        A CampaignCheck looks like this:
                        Code:
                        /**
                             * The unique id of the CampaignCheck.
                             */
                            private Long id;
                        
                            /**
                             * The Campaign to which the Check belongs.
                             */
                            private Campaign campaign;
                        
                            /**
                             * The Check that needs to be executed for the Campaign.
                             */
                            private Check check;
                        
                            /**
                             * Indicates whether this CampaignCheck is disabled or not.
                             */
                            private boolean disabled;
                        So when I check some values in the list, not only those should be retrieved but also those that weren't checked. (The value disabled should be set to true if it wasn't selected).

                        I guess the answer is just lying in front of me, but it's too early in the morning to think clear

                        Comment


                        • #13
                          http://commons.apache.org/collection...ase/index.html

                          http://code.google.com/p/google-collections/

                          Comment


                          • #14
                            Thank you so much for posting this...I was struggling with this exact problem for about 2 weeks before I stumbled upon your solution, which worked like a charm.

                            Brian French

                            Comment


                            • #15
                              Could you please give an example using annotated Controller instead? Is it possible?

                              Comment

                              Working...
                              X