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

  • #16
    as an experiment out of interest

    after some investigation, i would also conclude as with others that the wrapping object would be the most straightforward implementation, especially if you are using spring 2 form tags.

    However, there is something so deceptively attractive about adelinor's method to take advantage of spring automatic comma seperated binding, and there is a way to implement the view in a single line, using the function tag library. (only applies to spring bind tags)

    The key is this: fn: split(status.value, '/')[0]

    When getAsText() of your CustomDateEditor is called, it will return the formatted string, which you can split out.

    Example code:
    Code:
    <spring:bind path="command.dob">
    	<select name="${status.expression }" id="day">
    		<c:forEach items="${dayMap}" var="elem">
    			<option value="${elem.key}" <c:if test="${fn:split(status.value, '/')[0] eq elem.key}" >selected="selected"</c:if>>${elem.value }</option>
    		</c:forEach>		
    	</select>
    	<select name="${status.expression }" id="month">
    		<c:forEach items="${monthMap}" var="elem">
    			<option value="${elem.key}" <c:if test="${fn:split(status.value, '/')[1] eq elem.key}" >selected="selected"</c:if>>${elem.value }</option>
    		</c:forEach>				
    	</select>
    	<select name="${status.expression }" id="year">
    		<c:forEach items="${yearMap}" var="elem">
    			<option value="${elem.key}" <c:if test="${fn:split(status.value, '/')[2] eq elem.key}" >selected="selected"</c:if>>${elem.value }</option>
    		</c:forEach>
    	</select>
    </spring:bind>
    For completeness, here is the java code:

    Code:
    class CompositeCustomDateEditor extends CustomDateEditor{
        public CompositeCustomDateEditor(DateFormat dateFormat, boolean allowEmpty) {
            super(dateFormat, allowEmpty);
        }
        public void setAsText(String text) {
            if (text != null) {
              super.setAsText(text.replace(',', '/'));
            }
        }
    }
    
    public void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) throws Exception {
    
        SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");
        binder.registerCustomEditor( Date.class, "dob", new CompositeCustomDateEditor(dateFormat, true));		
    }
    You will notice that these dropdowns do not have the ability to be blank. This is because it would lead to a bug where if day was not selected, and month and year were selected, after submit, the custom editor cannot set a valid date, hence you would lose the values you selected for month and year. I don't think there is a way around this. As nekoval pointed out, there is no binding error support in custom editors.

    If you are binding composite string fields though, you can hack around this, see my next post below.

    Comment


    • #17
      do the following at your own peril

      As I stated above, this is not the best way to do it, but If you are binding composite String fields (e.g. phone number field, seperated into area code and phone number), then this method could be usable.

      Once again, applies to spring: bind tags only.

      java code:
      Code:
      /*	 custom editor that is able to join 2 composite phone number fields with a "-" */ 
      class CustomPhoneNumberEditor extends PropertyEditorSupport {
      		public CustomPhoneNumberEditor() {}
      		public void setAsText(String text) {
      			if (text != null) {
      				if (",".equals(text))
      					setValue(null);    // both fields were empty
      				else
      					setValue(text.replace(',', '-'));
      			}
      		}
      		public String getAsText() {
      			//so that textbox wont display "null"
      			if (getValue()==null)
      			    return null; 
      			
      			String result = (String)getValue();
      			
      			// fn:split doesn't support empty tokens
      			// this allows values to display properly when nothing was entered
      			if (result.startsWith("-")) 
      				result = " " + result;  
      			if (result.endsWith("-")) 
      				result = result + " ";
      			return result;
      		}
      	};
      	
      }
      public void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) throws Exception {
         binder.registerCustomEditor(String.class, "phoneNumber", new CustomPhoneNumberEditor());		
      }
      JSP code:

      Code:
      <spring:bind path="command.phoneNumber">
      	<input type="text" value="${fn:trim(fn:split(status.value, '-')[0])}" name="${status.expression }" />
      	<input type="text" value="${fn:trim(fn:split(status.value, '-')[1])}" name="${status.expression }" />
      </spring:bind>
      Following on from my previous post, this code solves the problem when you dont enter an area code, and you enter a phone number. This scenario will post ",91234567" which binds to "-91234567". When it returns to the JSP and you do a split, you won't have 2 elements in the list (since split doesn't support null tokens).

      The magic of the hack lies in manually detecting and changing your null tokens to a space " " , then using fn:trim to get rid of it again.

      So in conclusion, this was quite elegent in theory, but ended up looking like a big hack. I'd go with the wrapping object...

      Hope that may have been helpful to someone.

      Comment

      Working...
      X