Announcement Announcement Module
Collapse
No announcement yet.
Binding to collection properties with dynamic sizes Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Binding to collection properties with dynamic sizes

    We are having trouble bind to properties of objects within a dynamically sized collection. Our web form allows questions to be added or removed client-side using JavaScript. Each question has a couple of properties that we want to bind to.

    For example, an input for question 3 (at index 2) would look like this:
    <input name="command.questions[2].title" type="text"/>

    In this example "command" is our root binding object, which contains a list of "questions", each of which have a "title" property. We have addressed this with Spring MVC by using a LazyList (commons class, same as AutoPopulatingList) or by using a GrowingList (commons class). These override get/set methods on the List interface to automatically create questions as needed by the binding code.

    However, the EL binding code used by webflow doesn't simply call "get" or "set" on the list, but instead it calls size() and throws an exception if the size isn't large enough. (this is down in ListELResolver) In the previous example, since on the first binding, the questions list would be empty, the EL binding code calls size() which returns 0. Since we're trying to bind to a question at index 2, the binding code throws a PropertyNotFoundException.

    A workaround is to pre-populate the list of questions, but since the client-side DHTML can add or remove those, it's impossible to know how many will be needed for binding (hence our use of Lazy/GrowingList). Perhaps we could hack something together that passes the total number to the server in a hidden field, etc. but I'm not even sure how to hook into the web code prior to binding to do this. (is there a hook into the binding before the EL binding code runs? i.e. the ability to add objects into the collection before webflow tries to bind to the command object)

    I should also mention that binding to a collection of simple properties works fine. For example if my binding was just to "command.questions[3]" you could use a GrowthList. In this case the binding code calls questions.set( 3, "value") and the growth list automatically grows the size of the list to support this. However, "command.questions[3].title" does not work.

    Does anyone have a good solution for binding to properties of composite objects in lists when the number of objects in that list aren't predetermined?

    Thanks!
    Jeremy Haile
    Last edited by jhaile; Dec 10th, 2008, 03:11 PM.

  • #2
    I confirmed this doesn't work with AutoPopulatingList. It looks like org.jboss.el.ValueExpressionImpl.setValue() gets invoked for any additional items but the invocation results in an IndexOutOfBoundsException. Please raise an issue.

    Comment


    • #3
      Thanks for confirming. I opened a JIRA issue here: http://jira.springframework.org/browse/SWF-990

      Comment


      • #4
        Workaround?

        Hi Jeremy,

        As Webflow 3.0 is not yet there, did you find a workaround for this issue?

        Thanks a lot,
        Benoit

        Comment


        • #5
          This issue was registered as as bug (https://jira.springframework.org/browse/SWF-990) almost 3 years ago and is still not fixed. I bet there must be loads of people strugling with this issue and I would be really happy to see som progress beeing made to fix it. Still no workarounds anyone?

          Comment


          • #6
            I'm stuck on this one as well. Has anyone come up with a reasonable work-around?

            Originally posted by krise View Post
            This issue was registered as as bug (https://jira.springframework.org/browse/SWF-990) almost 3 years ago and is still not fixed. I bet there must be loads of people strugling with this issue and I would be really happy to see som progress beeing made to fix it. Still no workarounds anyone?

            Comment


            • #7
              Stuck there myself... 2013.. 5 years and still nothing?

              Comment


              • #8
                Don't wait for an answer. Nobody will help.
                http://forum.springsource.org/showth...t-What-s-wrong

                Comment


                • #9
                  I had to implement the functionality in a different way, but you said you succeed to bind an object to a list that did not have a corresponding object at the same index?

                  Comment


                  • #10
                    1.
                    Code:
                    import org.apache.commons.collections.list.LazyList;
                    
                    private List<MyEntity> indexedList = LazyList.decorate(
                            new ArrayList<MyEntity>(),
                            FactoryUtils.instantiateFactory(MyEntity.class));
                    That code helps with 'auto growing' for indexed property in form bean.

                    2.
                    When you remove something indexed, you have to store 'removed index number' in hidden field (usually by js code), pass it to server and remove 'indexed elements' by server side code using hidden values.
                    Code:
                            // get row ids to be removed from hidden field (0:1:2:3:6:8:)
                            String removeIds = externalContext.getRequestParameterMap().get("removedIds");
                    
                            // remove 'deleted entity' from bean using supplied ids
                            if(removeIds != null && removeIds.length() > 0) {
                                removeIds.trim();
                                String [] array = removeIds.split(":"); // split ids to be removed
                                String oneId = "";
                                if(array != null && array.length > 0) {
                                    for(int i = 0; i < array.length; i++) {
                                        oneId = array[i];
                                        if(oneId.length() > 0) {
                    //...........................  remove indexed property elements from form bean
                                        }
                                    }
                                }
                            }
                    Last edited by blandger; Apr 9th, 2013, 02:57 PM.

                    Comment


                    • #11
                      I hope it's obvious you should pass 'removed ids' by using webflow xml configuration for particular view state.

                      Code:
                          <view-state id=..........>
                              <on-entry>
                                  <set name="requestScope.removedIds" value="requestParameters.removedIds" type="string"/>
                              </on-entry>
                              <on-render>
                                  <evaluate expression="....................../>
                      ...............

                      Comment


                      • #12
                        but if webflow is checking for the size of the list before adding any element, how could this work? LazyList is returning a fake number?

                        Comment


                        • #13
                          As I as think, LazyList creates empty element(s) and makes it possible to bind 'new/added' indexed properties to it.
                          It just works, the internal details can be found from sources.

                          Comment


                          • #14
                            if is this: http://commons.apache.org/proper/com.../LazyList.html
                            there is no implementation of size method so it's the default one, it means it returns 0 elements when invoked and spring
                            code do exactly this when it raises that exception during binding. To me it does not work.

                            Comment

                            Working...
                            X