Announcement

Collapse
No announcement yet.
X
  • Filter
  • Time
Clear All
new posts

    Custom CheckBoxItem editor doesn't work

    Hi,

    SmartClient Version: SC_SNAPSHOT-2011-01-25/EVAL Deployment

    I created this standalone test case, because I believe there are some issues with extending the CheckBoxItem and thus creating our own custom CheckBoxItem.

    The initial value of the checkBox is not set correctly, it is always set to the default => "true".
    The reason "why" becomes clear as the EditorValueFormatter and EditorValueParser are never called?!?

    Something I find very strange, as my other custom editor types don't seem to have a problem with this, however, these other editors extend TextItem or ComboBoxItem.

    On the other hand, the input transformer is called! However, as the initial value is not set correctly, my oldValue is a javascriptobject (which I expect it to be) but my (new) value is "true"and not the value after the change?!? In other words, I'm getting the default value from the checkBox iso the clicked event.

    I also tried adding a valueMap, but that doesn't fix anything.
    My biggest issue is that the formatter or parser are not called.

    Please advice.

    Regards,
    Bart


    Code:
    public class Standalone implements EntryPoint {
    	
    	/**
    	 * Container for either the login window or the workspace;
    	 */
    	private static Canvas masterPanel = null;
    	
    	 public void onModuleLoad() {  
    		 		
    		//masterPanel should be a Layout
    		// this way, it will re-layout its members if the browser gets resized
    		masterPanel = new Canvas(); 
    		masterPanel.setHeight100();
    		masterPanel.setWidth100();
    		masterPanel.setStyleName("pageBackground"); //background style from skin
    		  
    	    DataSource dataSource = new DataSource();   
    	
    	    DataSourceField myCheckBoxField = new DataSourceField();   
    	    myCheckBoxField.setName("checkBoxField1");   
    	    myCheckBoxField.setTitle("checkBoxField1");   
    	    myCheckBoxField.setType(new MyCheckBoxType());   
    	    myCheckBoxField.setEditorType(new MyCheckBoxEditor());
    	
    	    dataSource.setFields(myCheckBoxField);   
    
    	    //the order list grid   
    	    DynamicForm form = new DynamicForm();   
    	    form.setHeight(170);   
    	    form.setWidth(500);
    	    form.setDataSource(dataSource);
      
    	    form.setValue("checkBoxField1", createBoolean("false"));
    	
    		masterPanel.addChild(form);
    		masterPanel.draw();	
    	}
    	 
    	public static JavaScriptObject createBoolean(String theBool){
    		JavaScriptObject jsObject = JSOHelper.createObject();
    		//this is needed for the 'undefined' state
    		if(theBool == null){
    
    			JSOHelper.setAttribute(jsObject, "booleanValue", theBool);
    
    		}
    		else{
    			JSOHelper.setAttribute(jsObject, "booleanValue", Boolean.parseBoolean(theBool));			
    		}
    		return jsObject;
    	}
        
        public static class MyCheckBoxType extends SimpleType {   
            public MyCheckBoxType() {   
                super("myCheckBoxType", FieldType.ANY);   
     
            }   
        }  
        
        private class MyCheckBoxEditor extends CheckboxItem {
    
        	private Boolean booleanValue;
    
        	public MyCheckBoxEditor() {
        		super();
        		this.setAllowEmptyValue(true);
        		this.setShowUnsetImage(true);
        		
        		this.setInputTransformer(new MyCheckBoxTransformer());
        		this.setEditorValueFormatter(new MyCheckBoxEditorFormatter());
        		this.setEditorValueParser(new MyCheckBoxValueParser());
        	}
        	
        	public class MyCheckBoxTransformer implements FormItemInputTransformer {
    		
    			@SuppressWarnings("unchecked")
    			public Object transformInput(DynamicForm form, FormItem item, Object value, Object oldValue) {
    	
    				if (value == null) {
    					return item.getValue();
    				}
    				
    				if(value instanceof Boolean){
    					
    					return createBoolean(((Boolean) value).toString());
    				}
    				
    				return createBoolean((String) value);
    			}
    	
    		}
    
        	
        	public class MyCheckBoxEditorFormatter implements FormItemValueFormatter {
    
        		public String formatValue(Object value, Record record, DynamicForm form, FormItem item) {
    
        			if (value == null)
        				return null;//undefined
    
        			if (value instanceof JavaScriptObject) {
        				JavaScriptObject object = (JavaScriptObject) value;
    
        				booleanValue = JSOHelper.getAttributeAsBoolean(object, "booleanValue");
    
        				return String.valueOf(booleanValue);
        			}
    
        			return (String) value;
        		}
    
        	}
        	
        	public class MyCheckBoxValueParser implements FormItemValueParser {
    
        		public Object parseValue(String value, DynamicForm form, FormItem item) {
        			boolean boolvalue = false;
    
        			if(value == null || value.length() < 1){
        				return item.getValue();
        			}
    
        			boolvalue = (value.equals("true") || value.equals("1"));
    
        			JavaScriptObject jsObject = null;
        			if (item.getValue() instanceof JavaScriptObject) {
        				jsObject = (JavaScriptObject) item.getValue();
        			}
        			
        			if (jsObject == null) return createBoolean(value);
        			JavaScriptObject newJsObject = JSOHelper.createObject();
        			JSOHelper.setAttribute(newJsObject, "booleanValue", boolvalue);
        			return newJsObject;
        		}
    
        	}
        }
        
    }

    #2
    The Formatter/Parser pair really apply to user text input.

    There's a bunch of low-level hacking here, but it's not clear what you're trying to achieve - can you explain the purpose of the component?

    Comment


      #3
      Ok, I'll explain in detail:

      Just like the smartGWT CheckboxItem our custom server types are not just plain true or false but ALSO true, false or undefined.

      That's why we extend the CheckBoxItem because this supports the undefined state in contrary to the NativeCheckBoxItem (if I remember correctly).

      As we use our own custom persistance framework, the value coming back from the server is not a simple boolean but our own custom server type for a boolean (which captures this undefined state). So, ipso facto we need a simple type in smartGWT to capture this behavior and to allow automatic data binding.

      I'm sorry to say, but my view is that this is not really different than any other custom editor. The only difference is that instead of a TextItem it's a CheckBoxItem. So, the "low level hacking" you are taking about is not really making much sense to me... implementing a formatter and parser is the first thing you need to do when creating your own custom type. Just to display the data correctly or to set the parsed value back to the original server type.

      Did you look at the input transformer issue?

      Regards,
      Bart

      Comment


        #4
        Input transformer is the same issue - it's designed for textual input, not a checkbox.

        What you want to do instead is to allow the CheckboxItem to use it's usual representation of the 3 states (true/false/undefined) and translate between how you store this vs how it's represented client-side in the data layer - either transformRequest/transformResponse, or server-side.

        This is a much cleaner and clearer approach because, aside from the eliminating the weird JSOHelper stuff you were trying to do, the client-side system elsewhere also expects booleans to have a certain internal representation, so this will avoid you having to override various other formatters and logic that checks the value of a boolean field.

        Comment


          #5
          Hi Isomorphic,

          We don't use transformRequest/transformResponse for the other types, so I don't want to implement this just for this type.

          I mean, you could just couple any JavaClass to the datasource field, not just a boolean, correct?
          What you are saying now is that it will only work with a boolean?

          The thing is that the framework is creating a JavascriptObject which correctly reflects my custom type (via JavaClass), it's even
          setting this JavascriptObject as value of my CheckBoxItem but it's not able to interprete this value.
          I agree that this is normal, but I should have the ability (somewhere) to do this, so I can drive the check box.

          Example of the datasource xml:

          Code:
          <field name="isCorporateLanguage" title="Is Corporate Language" type="silkBoolean" javaClass="parameter.SraBoolean" required="true" >
          From Dev Console:

          Code:
                              isCorporateLanguage:{
                                  booleanValue:true, 
                                  dataType:12, 
                                  defaultValue:"true"
                              },
          http://www.smartclient.com/smartgwte...html#javaClass

          Regards,
          Bart
          Last edited by bade; 4 Mar 2011, 03:33.

          Comment


            #6
            By design, CheckBoxItem does not support the ValueParser/ValueFormatter APIs. Boolean fields can have a custom editorType, but you cannot change the internal representation of a Boolean value (because this is a waste of time and more complicated than other approaches).

            Comment


              #7
              After giving this some thought, I switched to using the dataPath feature for this custom type because basicaly my custom object is just a wrapper around a Boolean.

              This gives me the benefit that I can keep working with my custom type (and don't need to change our framework).

              My question is if this approach is supported or do you have another insight?

              Comment


                #8
                Yes, that approach is fine. The underlying value needs to be a Boolean, so if there's a Boolean value somewhere and it's reachable via dataPath, that works.

                Comment

                Working...
                X