Announcement Announcement Module
Collapse
No announcement yet.
binding dynamic number of text boxes Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • binding dynamic number of text boxes

    I have a requirement that seems to be an extension of binding checkboxes.

    Let's say I have a list of possible phone number types (home, business, cell). This list is to be displayed on a jsp page (in a specific order) where a user can enter 0 or more phone number values using input boxes.

    I've searched through similar posts and have pieced together an initial solution to my problem. I have the jsp displaying the phone number types in order and have values being associated with the correct types. If I submit the form, no errors occur but nothing happens as well since I haven't implemented any binding logic.

    I've looked at posts related to custom PropertyEditors but can't seem to wrap my head around the way Spring binds data yet. Am I correct in assuming that implementation of a PropertyEditor will handle re-populating the text boxes with entered values after a validation failure?

    Am I on the right track? What should be my next step in terms of binding the data to my object model?

    Any help is appreciated.

    Here's what I have so far:

    A basic phone number class which I reuse for both the available and current list:

    Code:
    public class PhoneNumber {
    
        String type = null;
        String description = null;
        String value = null;
    
        ... getters and setters
    }
    In my command object I store the current phone numbers using a List:

    Code:
    public class User {
    
        List phoneNumbers = null;
        ... getters and setters
    }
    In my controller's referenceData() I hardcode the available list:

    Code:
    List phoneNumbers = new ArrayList();
            PhoneNumber f = new PhoneNumber();
            f.setType("C");
            f.setDescription("Cellular");
            phoneNumbers.add(f);
            PhoneNumber d = new PhoneNumber();
            d.setType("H");
            d.setDescription("Home");
            phoneNumbers.add(d);
            PhoneNumber e = new PhoneNumber();
            e.setType("B");
            e.setDescription("Business");
            phoneNumbers.add(e);
    
            data.put("phoneNumberList", phoneNumbers);
    In my controller's formBackingObject, I hardcode phone number values:

    Code:
    List phoneNumbers = new ArrayList();
                PhoneNumber a = new PhoneNumber();
                a.setType("H");
                a.setValue("111 111-1111");
                phoneNumbers.add(a);
                PhoneNumber b = new PhoneNumber();
                b.setType("B");
                b.setValue("222 222-2222");
                phoneNumbers.add(b);
                form.setPhoneNumbers(phoneNumbers);
    In my jsp I combine everything together. Not sure how the <spring:bind> tag is used in this case:

    Code:
    <c:forEach items="${phoneNumberList}" var="phoneNumber">
                <tr>
                    <td>${phoneNumber.description}</td>
                    <td>
                        <spring:bind path="command.phoneNumbers">
                            <c:set var="found" value="false"/>
                            <c:forEach items="${command.phoneNumbers}" var="phoneNumberValue">
                                <c:if test="${phoneNumberValue.type == phoneNumber.type}">
                                    <c:set var="found" value="true"/>
                                    <input type="text" name="phone${phoneNumber.type}" value="${phoneNumberValue.value}" />
                                </c:if>
                            </c:forEach>
                            <c:if test="${found == 'false'}">
                                <input type="text" name="phone${phoneNumber.type}" value="" />
                            </c:if>
                        </spring:bind>
                    </td>
                </tr>
            </c:forEach>
    and finally when I view page source, i get what I expected:

    Code:
    <tr>         
                    <td>Cellular</td>
                    <td>
                            <input type="text" name="phoneC" value="" />
                    </td>
                </tr>
                <tr>
                    <td>Home</td>
                    <td>   
                                <input type="text" name="phoneH" value="111 111-1111" />
                    </td>
                </tr>
                <tr>
                    <td>Business</td>
                    <td>     
                                <input type="text" name="phoneB" value="222 222-2222" />
                    </td>
                </tr>

  • #2
    In this case, the property backing the phone number is User.phoneNumbers, which is a List. So Spring binder will be looking for a request parameter called "phoneNumbers", and use whatever property editor registered for this property and type to do the actual binding.

    You can try naming all the input textboxes the same name "phoneNumbers", so at submission time they will be submitted as comma separated list with parameter name "phoneNumbers". On the server side you can simply registered a custom property editor (possibly extending Spring's CustomCollectionEditor) for that property.

    Another way, if you want to stay the way you are naming your input boxes now, is to simply override onBind() and bind those by yourself.

    Comment


    • #3
      Thanks!

      In the same parameter name suggestion, how does spring determine which type of phone number to create with just a comma separated list?

      I was able to get it working with your second method. This seems to be the most straightforward to understand (for me) and will handle more complex obects. I assume this means that since I'm binding these values manually, I no longer need the <spring:bind> tag in my jsp. Is this correct?

      For validation, would I add more logic to the jsp to manually map validation errors to each phone type? I'm currently using commons validator and don't think it can handle this scenario via validation.xml mapping.

      Comment


      • #4
        I'm also considering yatesco's approach here which combines the available and selected values on the server side instead of on the jsp.

        Not sure if it will simplify binding (how will it know what phone type to associate a value to) and validation though.

        Comment


        • #5
          Originally posted by devel28
          In the same parameter name suggestion, how does spring determine which type of phone number to create with just a comma separated list?
          It doesn't. It delegates the binding logic, along with the whole list as a string, to the particular property editor registered for the collection type and optionally the property name - in your case, the List type and the 'phoneNumbers' property.

          Originally posted by devel28
          I was able to get it working with your second method. This seems to be the most straightforward to understand (for me) and will handle more complex obects. I assume this means that since I'm binding these values manually, I no longer need the <spring:bind> tag in my jsp. Is this correct?
          Well, the <spring:bind> tag in the jsp code you posted earlier doesn't have much effect anyways, because you are not using any variables it exposes in the enclosing scope.

          This is actually where "bind" is a bit overloaded . <spring:bind>, IMHO, actually doesn't directly relate to the binding process during form submission. <spring:bind> is a convenient tag to bind the value, name, and error messages (collectively referred to as "status") of a property to jsp scripting variables. It makes it a lot easier and less error-prone to render a form that will eventually come back to the server-side of the binding process, where "binding" as in "parsing request parameters into command properties."

          Originally posted by devel28
          For validation, would I add more logic to the jsp to manually map validation errors to each phone type? I'm currently using commons validator and don't think it can handle this scenario via validation.xml mapping.
          Yes, you probably have to do that with some custom code as well, if you want to sort the error messages out to individual phone number level.

          Comment


          • #6
            It doesn't. It delegates the binding logic, along with the whole list as a string, to the particular property editor registered for the collection type and optionally the property name - in your case, the List type and the 'phoneNumbers' property.
            Given just a string of values something like "value1,value2,,value4", how would I know what phone number type each value is associated with?

            I cleaned up the jsp code by combining the available and selected phone number objects on the server. I then bind these objects to text boxes using <spring:bind>.

            I tried using a List which worked but found that binding the values on the server was dependent on the index value. I would receive a list of objects like phoneNumbers[0], phoneNumbers[1] and have to know that the first element was of a certain phone type. I'm now using a LinkedHashMap so that I get values in the form of phoneNumbers[home], phoneNumbers[business] but still retain the ordering for display purposes.

            my jsp now looks something like this:

            Code:
            <c:forEach items="${command.phoneNumbers}" var="phoneNumber">
                        <tr>
                            <td>${phoneNumber.value.description}</td>
                            <td>
                                <spring:bind path="command.phoneNumbers[${phoneNumber.key}]">
                                    <input type="text" name="${status.expression}" value="${status.value.value}" />
                                </spring:bind>
                            </td>
                        </tr>
                    </c:forEach>
            The downside is that this method won't handle a more complicated PhoneNumber object (like adding a new area code property) like my original code will.

            Yes, you probably have to do that with some custom code as well, if you want to sort the error messages out to individual phone number level.
            I'm hoping that a spring Validator should now do the trick.

            Thanks again for your help.
            Last edited by devel28; Jul 16th, 2006, 12:49 PM.

            Comment

            Working...
            X