Announcement

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

    Custom Editor on FilterBuilder - JS crash on getValue()

    I'm trying to build a custom TextItem for use in both a Form and a FilterBuilder. This TextItem has a FormItemIcon that when clicked brings up a canvas with a field on it, and a save and cancel button. The save button has a callback on it that tries to set the value of the field on the canvas as the value of the custom TextItem. When using this on a form, it works fine, but when using it as the EditorType on a DataSourceTextField used by a FilterBuilder the value doesn't get set, and when I call getValue() on the TextItem, I get the Java Script Error below.

    I posted about a very similar problem with a custom editor on a ListGrid here: http://forums.smartclient.com/showthread.php?t=13032

    I've built a test case based on the CustomDS example. After the JavaScript error is the code and also attached.

    I'm running with the nightly build of SmartGWT Pro from Sep 9, 2010 on Firefox 3.6.10 on XP SP3.

    Thanks for your help.

    JavaScript:
    Code:
    Uncaught exception escaped : com.google.gwt.core.client.JavaScriptException
    (TypeError): self.getValue is not a function
     fileName: http://127.0.0.1:8888
     lineNumber: 352
     stack: ()@http://127.0.0.1:8888:352
    @:0
    ([object GWTJavaObject],3014818,[object GWTJavaObject])@http://127.0.0.1:8888/customds/hosted.html?customds:56
    ([object Object],(void 0))@http://127.0.0.1:8888:1434
    ((function () {var param = {};var event = __gwt_makeJavaInvoke(1)(null, 5242919, param);__gwt_makeJavaInvoke(1)(selfJ, 3014818, event);var ret = __gwt_makeJavaInvoke(0)(event, 1179649);return !ret;}),[object Object],[object Object])@http://127.0.0.1:8888:6
    @:0
    (null,65563,(function () {var param = {};var event = __gwt_makeJavaInvoke(1)(null, 5242919, param);__gwt_makeJavaInvoke(1)(selfJ, 3014818, event);var ret = __gwt_makeJavaInvoke(0)(event, 1179649);return !ret;}),[object Object],[object Object])@http://127.0.0.1:8888/customds/hosted.html?customds:56
    ([object Object],(void 0))@http://127.0.0.1:8888:41
    ([object Object],(void 0))@http://127.0.0.1:8888:13
    isc_StatefulCanvas_handleActivate([object Object],(void 0))@http://127.0.0.1:8888/customds/sc/modules/ISC_Foundation.js:318
    isc_StatefulCanvas_handleClick([object Object],(void 0))@http://127.0.0.1:8888/customds/sc/modules/ISC_Foundation.js:320
    isc_c_EventHandler_bubbleEvent([object Object],"click")@http://127.0.0.1:8888/customds/sc/modules/ISC_Core.js:1539
    isc_c_EventHandler_handleClick([object Object])@http://127.0.0.1:8888/customds/sc/modules/ISC_Core.js:1392
    isc_c_EventHandler__handleMouseUp([object MouseEvent],(void 0))@http://127.0.0.1:8888/customds/sc/modules/ISC_Core.js:1379
    isc_c_EventHandler_handleMouseUp([object MouseEvent])@http://127.0.0.1:8888/customds/sc/modules/ISC_Core.js:1370
    isc_c_EventHandler_dispatch(isc_c_EventHandler_handleMouseUp,[object MouseEvent])@http://127.0.0.1:8888/customds/sc/modules/ISC_Core.js:1602
    anonymous([object MouseEvent])@http://127.0.0.1:8888/customds/sc/modules/ISC_Core.js:60
    CustomDS.java
    Code:
    package com.smartgwt.sample.client;
    
    
    import com.google.gwt.core.client.EntryPoint;
    import com.google.gwt.core.client.GWT;
    import com.smartgwt.client.core.KeyIdentifier;
    import com.smartgwt.client.data.DataSource;
    import com.smartgwt.client.data.fields.DataSourceBooleanField;
    import com.smartgwt.client.data.fields.DataSourceDateField;
    import com.smartgwt.client.data.fields.DataSourceFloatField;
    import com.smartgwt.client.data.fields.DataSourceSequenceField;
    import com.smartgwt.client.data.fields.DataSourceTextField;
    import com.smartgwt.client.types.CharacterCasing;
    import com.smartgwt.client.util.KeyCallback;
    import com.smartgwt.client.util.Page;
    import com.smartgwt.client.util.SC;
    import com.smartgwt.client.widgets.form.DynamicForm;
    import com.smartgwt.client.widgets.form.FilterBuilder;
    import com.smartgwt.client.widgets.layout.VStack;
    
    
    /**
     * Entry point classes define <code>onModuleLoad()</code>.
     */
    public class CustomDS implements EntryPoint
    {
    
    	/**
    	 * This is the entry point method.
    	 */
    	public void onModuleLoad()
    	{
    
    		KeyIdentifier debugKey = new KeyIdentifier();
    		debugKey.setCtrlKey( true );
    		debugKey.setKeyName( "D" );
    
    		Page.registerKey( debugKey, new KeyCallback()
    		{
    			public void execute(String keyName)
    			{
    				SC.showConsole();
    			}
    		} );
    
    		// instantiate DataSource on the client only (this example explicitly bypasses
    		// ISC server-side DataSource management)
    
    		DataSource dataSource = new DataSource();
    		dataSource.setDataURL( GWT.getModuleBaseURL() + "/supplyItemOperations.rpc" );
    		dataSource.setID( "supplyItem" );
    
    		DataSourceSequenceField itemID = new DataSourceSequenceField( "itemID" );
    		itemID.setPrimaryKey( true );
    		itemID.setHidden( true );
    
    		DataSourceTextField itemName = new DataSourceTextField( "itemName", "Item", 128, true );
    		CustomTextItem cti = new CustomTextItem();
    		cti.setCharacterCasing( CharacterCasing.UPPER );
    		itemName.setEditorType( cti );
    
    		DataSourceTextField SKU = new DataSourceTextField( "SKU", "SKU", 10 );
    		//SKU.setCanFilter(false);
    
    		DataSourceTextField description = new DataSourceTextField( "description", "Description" );
    		DataSourceTextField category = new DataSourceTextField( "category", "Category", 128 );
    		DataSourceTextField units = new DataSourceTextField( "units", "Units", 5 );
    
    		DataSourceFloatField unitCost = new DataSourceFloatField( "unitCost", "Unit Cost" );
    		DataSourceBooleanField inStock = new DataSourceBooleanField( "inStock", "In Stock" );
    
    		DataSourceDateField nextShipment = new DataSourceDateField( "nextShipment", "Next Shipment" );
    
    		dataSource.setFields( itemID, itemName, SKU, description, category, units, unitCost, inStock, nextShipment );
    
    		VStack vStack = new VStack();
    		vStack.setLeft( 175 );
    		vStack.setTop( 75 );
    		vStack.setWidth( "70%" );
    		vStack.setMembersMargin( 20 );
    
    		FilterBuilder filterBuilder = new FilterBuilder();
    		filterBuilder.setDataSource( dataSource );
    		vStack.addMember( filterBuilder );
    		
    		DynamicForm form = new DynamicForm();
    		CustomTextItem itemField = new CustomTextItem();
    		itemField.setTitle( "Item" );
    		form.setFields( itemField );
    		vStack.addMember( form );
    
    		vStack.draw();
    	}
    }
    CustomTextItem.java
    Code:
    package com.smartgwt.sample.client;
    
    import com.smartgwt.client.util.EventHandler;
    import com.smartgwt.client.widgets.form.fields.FormItem;
    import com.smartgwt.client.widgets.form.fields.FormItemIcon;
    import com.smartgwt.client.widgets.form.fields.TextItem;
    import com.smartgwt.client.widgets.form.fields.events.IconClickEvent;
    import com.smartgwt.client.widgets.form.fields.events.IconClickHandler;
    
    public class CustomTextItem extends TextItem
    {
    	private CustomCanvas customCanvas;
    
    	public CustomTextItem()
    	{
    		FormItemIcon formItemIcon = new FormItemIcon();
    		setIcons( formItemIcon );
    		customCanvas = new CustomCanvas();
    
    		addIconClickHandler( new IconClickHandler()
    		{
    			@Override
    			public void onIconClick(IconClickEvent event)
    			{
    				System.out.println( "getValue() is " + event.getItem().getValue() );
    
    				FormItem formItem = event.getItem();
    				customCanvas.setValue( (String) formItem.getValue() );
    
    				customCanvas.setTop( EventHandler.getY() );
    				customCanvas.setLeft( EventHandler.getX() );
    				customCanvas.show();
    				customCanvas.bringToFront();
    			}
    		} );
    
    		customCanvas.registerCancelHandler( new ClickCallback()
    		{
    			@Override
    			public void onClick()
    			{
    				customCanvas.hide();
    			}
    		} );
    
    		customCanvas.registerSaveHandler( new CustomTextItemCallback( CustomTextItem.this ) );
    
    	}
    
    	public class CustomTextItemCallback implements ObjectCallback
    	{
    		CustomTextItem myCustomTextItem;
    
    		public CustomTextItemCallback(CustomTextItem customTextItem)
    		{
    			myCustomTextItem = customTextItem;
    		}
    
    		@Override
    		public void execute(Object value)
    		{
    			customCanvas.hide();
    			System.out.println( "CustomTextItem, value = " + value );
    			myCustomTextItem.setValue( (String) value );
    			System.out.println( "myCustomTextItem.getValue() = " + myCustomTextItem.getValue() );
    		}
    	}
    
    }
    CustomCanvas.java
    Code:
    package com.smartgwt.sample.client;
    
    import com.google.gwt.event.shared.HandlerRegistration;
    import com.smartgwt.client.types.Alignment;
    import com.smartgwt.client.widgets.Canvas;
    import com.smartgwt.client.widgets.IButton;
    import com.smartgwt.client.widgets.events.ClickHandler;
    import com.smartgwt.client.widgets.form.DynamicForm;
    import com.smartgwt.client.widgets.form.fields.TextItem;
    import com.smartgwt.client.widgets.layout.HLayout;
    import com.smartgwt.client.widgets.layout.VLayout;
    
    
    public class CustomCanvas extends Canvas
    {
    	private TextItem item;
    
    	IButton saveButton;
    
    	final IButton cancelButton;
    
    	public CustomCanvas()
    	{
    		super( );
    		this.setBackgroundColor( "#FFFFFF" );
    		this.setBorder( "2px solid" );
    		this.setWidth( 255 );
    		this.setHeight( 100 );
    
    		VLayout vlayout = new VLayout( 10 );
    		vlayout.setPadding( 10 );
    
    		DynamicForm itemForm = new DynamicForm();
    		itemForm.setWidth( "100%" );
    
    		item = new TextItem();
    		item.setTitle( "Item" );
    		item.setWidth( 200 );
    		itemForm.setItems( item );
    		
    		vlayout.addMember( itemForm );
    		
    		HLayout hlayout = new HLayout();
    		hlayout.setWidth( 255 );
    		hlayout.setAlign( Alignment.CENTER );	
    
    		saveButton = new IButton( "Save" );
    
    		cancelButton = new IButton( "Cancel" );
    
    		DynamicForm spacer1 = new DynamicForm();
    		spacer1.setWidth( 10 );
    
    		hlayout.addMember( saveButton );
    		hlayout.addMember( spacer1 );
    		hlayout.addMember( cancelButton );
    
    		vlayout.addMember( hlayout );
    		addChild( vlayout );
    	}
    
    	public HandlerRegistration registerSaveHandler(final ObjectCallback callback)
    	{
    		return saveButton.addClickHandler( new ClickHandler()
    		{
    			public void onClick(com.smartgwt.client.widgets.events.ClickEvent event)
    			{
    				String value = ((String)item.getValue()) + " plus a modification.";
    				callback.execute( value );
    			}
    		} );
    	}
    
    	public HandlerRegistration registerCancelHandler(final ClickCallback callback)
    	{
    		return cancelButton.addClickHandler( new ClickHandler()
    		{
    			public void onClick(com.smartgwt.client.widgets.events.ClickEvent event)
    			{
    				callback.onClick();
    			}
    		} );
    	}
    
    	/**
    	 * @param value
    	 */
    	public void setValue(String value)
    	{
    		item.setValue( value );		
    	}
    
    }
    ObjectCallback.java
    Code:
    package com.smartgwt.sample.client;
    
    public interface ObjectCallback
    {
    	void execute(Object value);
    
    }
    ClickCallback.java
    Code:
    package com.smartgwt.sample.client;
    
    public interface ClickCallback
    {
    	void onClick();
    }
    Attached Files

    #2
    Any feedback on this? - I am also interested in a resolution.

    Comment


      #3
      So the DynamicForm works and calling getValue() on the CustomTextItem also returns the correct value. You're only having an issue with FilterBuilder, right?

      Can you post a screenshot of sample because it appears from your description that you are seeing your custom text item in the FilterBuilder while I'm not.

      Sanjiv

      Comment


        #4
        Thanks Sanjiv. You have it correct, I'm only having the issue with a FilterBuilder.

        Attached are a screen shot of the FilterBuilder using the CustomTextItem, about to save a value.

        The next screen shot is the resulting JavaScriptException after the Save button has been clicked.
        Attached Files

        Comment


          #5
          The problem with the original code had the call to
          Code:
          customCanvas.registerSaveHandler( new CustomTextItemCallback( CustomTextItem.this ) );
          which again treats the CustomTextItem object passed to DataSourceField.setEditorType(..) as the actual instance of the field rendered by the FilterBuilder which is not the case. As mentioned in the other related thread

          When you supply a custom FormItem via setEditorType(), you're really providing properties which are then used to create multiple FormItems (eg, in grids, forms and trees) and there's an underlying limitation here where event handlers have to be written to dynamically receive the actual FormItem rather than relying on "this" (because there's more than one "this").

          To get an actual handle on the formItem, use the FormItem instance from an event obtained via getItem(). Instead of calling this.focusInItem() call event.getItem().focusInItem().
          With this in mind, you can resolve the issue by making CustomCanvas a local variable within the addIconClickHandler and pass it the "real" FormItem that is obtained from IconClickEvent.getItem. The cancel callback stuff can remain as is but I've also simplified the code to get rid it it. The CustomCanvas simply adds a click handler to the cancel button that hides the Canvas.

          Here's the updated code :

          Code:
          import com.smartgwt.client.util.EventHandler;
          import com.smartgwt.client.widgets.form.fields.FormItem;
          import com.smartgwt.client.widgets.form.fields.FormItemIcon;
          import com.smartgwt.client.widgets.form.fields.TextItem;
          import com.smartgwt.client.widgets.form.fields.events.IconClickEvent;
          import com.smartgwt.client.widgets.form.fields.events.IconClickHandler;
          
          public class CustomTextItem extends TextItem {
              public CustomTextItem() {
                  FormItemIcon formItemIcon = new FormItemIcon();
                  setIcons(formItemIcon);
          
          
                  addIconClickHandler(new IconClickHandler() {
                      @Override
                      public void onIconClick(IconClickEvent event) {
                          FormItem formItem = event.getItem();
                          System.out.println("getValue() is " + event.getItem().getValue());
          
                          CustomCanvas customCanvas = new CustomCanvas(formItem);
                          customCanvas.setTop(EventHandler.getY());
                          customCanvas.setLeft(EventHandler.getX());
                          customCanvas.show();
                          customCanvas.bringToFront();
                      }
                  });
              }
          }
          Code:
          import com.smartgwt.client.types.Alignment;
          import com.smartgwt.client.widgets.Canvas;
          import com.smartgwt.client.widgets.IButton;
          import com.smartgwt.client.widgets.events.ClickEvent;
          import com.smartgwt.client.widgets.events.ClickHandler;
          import com.smartgwt.client.widgets.form.DynamicForm;
          import com.smartgwt.client.widgets.form.fields.FormItem;
          import com.smartgwt.client.widgets.form.fields.TextItem;
          import com.smartgwt.client.widgets.layout.HLayout;
          import com.smartgwt.client.widgets.layout.VLayout;
          
          
          public class CustomCanvas extends Canvas {
          
              public CustomCanvas(final FormItem filterBuilderFormItem) {
                  super();
                  this.setBackgroundColor("#FFFFFF");
                  this.setBorder("2px solid");
                  this.setWidth(255);
                  this.setHeight(100);
          
                  VLayout vlayout = new VLayout(10);
                  vlayout.setPadding(10);
          
                  DynamicForm itemForm = new DynamicForm();
                  itemForm.setWidth("100%");
          
                  final TextItem item = new TextItem();
                  item.setTitle("Item");
                  item.setWidth(200);
                  itemForm.setItems(item);
          
                  vlayout.addMember(itemForm);
          
                  HLayout hlayout = new HLayout();
                  hlayout.setWidth(255);
                  hlayout.setAlign(Alignment.CENTER);
          
                  IButton saveButton = new IButton("Save");
          
                  IButton cancelButton = new IButton("Cancel");
          
                  DynamicForm spacer1 = new DynamicForm();
                  spacer1.setWidth(10);
          
                  hlayout.addMember(saveButton);
                  hlayout.addMember(spacer1);
                  hlayout.addMember(cancelButton);
          
                  vlayout.addMember(hlayout);
                  addChild(vlayout);
          
                  item.setValue((String) filterBuilderFormItem.getValue());
          
                  saveButton.addClickHandler(new ClickHandler() {
                      public void onClick(com.smartgwt.client.widgets.events.ClickEvent event) {
                          String value = ((String) item.getValue()) + " plus a modification.";
                          filterBuilderFormItem.setValue(value);
                          CustomCanvas.this.hide();
                      }
                  });
          
                  cancelButton.addClickHandler(new ClickHandler() {
                      @Override
                      public void onClick(ClickEvent event) {
                          CustomCanvas.this.hide();
                      }
                  });
          
              }
          }

          The CustomDS EntryPoint class remains unchanged.

          Note that when I initially ran your test I was simply getting a text field show without the CustomTextItem properties being applied despite itemName.setEditorType(new CustomTextItem()) being called. A fix was made to resolve this but its still unclear how it did apply for you as shown in your screenshot. Anyways if you do run into this, then pick up the next nightly build.

          Sanjiv

          Comment


            #6
            It didn't really sink into my head that when you call setEditorType on the FilterBuilder with an object, you are really using the properties and type of that object, not the actual instance. It seems counter-intuitive.

            What you have shown to do here worked for me in my real-world code. Thanks Sanjiv for your for help and advice.

            I'm not sure why my original example worked for me, but not for you. I was running the SmartGWT Pro nightly build from September 10th.

            Nevertheless, my problem is fixed. Thank you!

            Comment

            Working...
            X