Announcement

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

    ListGrid getField or setFieldTitle after calling setDataSource

    Isomorphic SmartClient/SmartGWT Framework (v9.1p_2014-03-31/PowerEdition Deployment 2014-03-31)

    I'm moving some code from 4.0 to 4.1 and I found an issue where the code is getting null pointer exceptions. These are happening because of calls to either ListGrid.getField or ListGrid.setFieldTitle immediately after calling setDataSource.

    Here is an example of some code:
    Code:
      this.myListGrid.setDataSource( DataSource.get("mydatasource") );
      final Map< String, String > icons= new HashMap< String, String >();
      icons.put( "1", "../images/check-icon.png" );
    
      final ListGridField fieldEnabled= this.myListGrid.getField( "enabledField" );
    
      fieldEnabled.setValueIcons(icons);
      fieldEnabled.setShowValueIconOnly(true);
    This worked in 4.0, but now gets a null returned from getField. With 4.1, does the datasource field creation happen later than it did before? At what point are the fields created so that I know it is safe to retrieve them?

    #2
    There's been no intentional change in timing here and this method should never result in an NPE.

    Can you show the NullPointerException stack trace? Please always include this. Also, please let us know what browser(s) you see this in (again, always).

    As far as avoiding this - take a look at the QuickStart Guide, Data Binding chapter, for the suggested way to customize fields, which is both more efficient and avoids any possible lifecycle issue with fields.

    Comment


      #3
      The stack trace from a getField call isn't of much use since getField simply returns null, and the stack trace will simply show where our code is referencing it. Therefore, here is a stack trace where we've called setFieldTitle:

      Code:
      com.google.gwt.core.client.JavaScriptException(TypeError) @com.smartgwt.client.widgets.grid.ListGrid::setFieldTitle(Ljava/lang/String;Ljava/lang/String;)([string: 'authk_name', string: 'Name']): _2 is undefined: (TypeError) @com.smartgwt.client.widgets.grid.ListGrid::setFieldTitle(Ljava/lang/String;Ljava/lang/String;)([string: 'authk_name', string: 'Name']): _2 is undefined
      	at com.google.gwt.dev.shell.BrowserChannelServer.invokeJavascript(BrowserChannelServer.java:249)
      	at com.google.gwt.dev.shell.ModuleSpaceOOPHM.doInvoke(ModuleSpaceOOPHM.java:136)
      	at com.google.gwt.dev.shell.ModuleSpace.invokeNative(ModuleSpace.java:571)
      	at com.google.gwt.dev.shell.ModuleSpace.invokeNativeVoid(ModuleSpace.java:299)
      	at com.google.gwt.dev.shell.JavaScriptHost.invokeNativeVoid(JavaScriptHost.java:107)
      	at com.smartgwt.client.widgets.grid.ListGrid.setFieldTitle(ListGrid.java)
      	at myapplication.client.system.auth.AuthProfileKerberos$KerberosListPart.<init>(AuthProfileKerberos.java:69)
      	at myapplication.client.system.auth.AuthProfileKerberos.createList(AuthProfileKerberos.java:45)
      	at myapplication.client.common.components.AbstractDividedPane.initialize(AbstractDividedPane.java:41)
      	at myapplication.client.common.PaneFactory.createPane(PaneFactory.java:23)
      	at myapplication.client.common.PaneTabSet.createTab(PaneTabSet.java:519)
      	at myapplication.client.common.PaneTabSet.createNewTab(PaneTabSet.java:403)
      	at myapplication.client.common.PaneTabSet.showTab(PaneTabSet.java:389)
      	at myapplication.client.MainScreen$3.onPaneCall(MainScreen.java:291)
      	at myapplication.client.common.event.PaneCallEvent.dispatch(PaneCallEvent.java:45)
      	at myapplication.client.common.event.PaneCallEvent.dispatch(PaneCallEvent.java:1)
      	at com.google.gwt.event.shared.GwtEvent.dispatch(GwtEvent.java:1)
      	at com.google.web.bindery.event.shared.EventBus.dispatchEvent(EventBus.java:40)
      	at com.google.web.bindery.event.shared.SimpleEventBus.doFire(SimpleEventBus.java:193)
      	at com.google.web.bindery.event.shared.SimpleEventBus.fireEvent(SimpleEventBus.java:88)
      	at com.google.gwt.event.shared.HandlerManager.fireEvent(HandlerManager.java:127)
      	at myapplication.client.common.Navigator$1.onPaneCall(Navigator.java:58)
      	at myapplication.client.common.event.PaneCallEvent.dispatch(PaneCallEvent.java:45)
      	at myapplication.client.common.event.PaneCallEvent.dispatch(PaneCallEvent.java:1)
      	at com.google.gwt.event.shared.GwtEvent.dispatch(GwtEvent.java:1)
      	at com.google.web.bindery.event.shared.EventBus.dispatchEvent(EventBus.java:40)
      	at com.google.web.bindery.event.shared.SimpleEventBus.doFire(SimpleEventBus.java:193)
      	at com.google.web.bindery.event.shared.SimpleEventBus.fireEvent(SimpleEventBus.java:88)
      	at com.google.gwt.event.shared.HandlerManager.fireEvent(HandlerManager.java:127)
      	at myapplication.client.system.SystemSettings$1.onLeafClick(SystemSettings.java:144)
      	at com.smartgwt.client.widgets.tree.events.LeafClickEvent.dispatch(LeafClickEvent.java:110)
      	at com.smartgwt.client.widgets.tree.events.LeafClickEvent.dispatch(LeafClickEvent.java:1)
      	at com.google.gwt.event.shared.GwtEvent.dispatch(GwtEvent.java:1)
      	at com.google.web.bindery.event.shared.EventBus.dispatchEvent(EventBus.java:40)
      	at com.google.web.bindery.event.shared.SimpleEventBus.doFire(SimpleEventBus.java:193)
      	at com.google.web.bindery.event.shared.SimpleEventBus.fireEvent(SimpleEventBus.java:88)
      	at com.google.gwt.event.shared.HandlerManager.fireEvent(HandlerManager.java:127)
      	at com.google.gwt.user.client.ui.Widget.fireEvent(Widget.java:129)
      	at sun.reflect.GeneratedMethodAccessor94.invoke(Unknown Source)
      	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      	at java.lang.reflect.Method.invoke(Method.java:606)
      	at com.google.gwt.dev.shell.MethodAdaptor.invoke(MethodAdaptor.java:103)
      	at com.google.gwt.dev.shell.MethodDispatch.invoke(MethodDispatch.java:71)
      	at com.google.gwt.dev.shell.OophmSessionHandler.invoke(OophmSessionHandler.java:172)
      	at com.google.gwt.dev.shell.BrowserChannelServer.reactToMessagesWhileWaitingForReturn(BrowserChannelServer.java:338)
      	at com.google.gwt.dev.shell.BrowserChannelServer.invokeJavascript(BrowserChannelServer.java:219)
      	at com.google.gwt.dev.shell.ModuleSpaceOOPHM.doInvoke(ModuleSpaceOOPHM.java:136)
      	at com.google.gwt.dev.shell.ModuleSpace.invokeNative(ModuleSpace.java:571)
      	at com.google.gwt.dev.shell.ModuleSpace.invokeNativeObject(ModuleSpace.java:279)
      	at com.google.gwt.dev.shell.JavaScriptHost.invokeNativeObject(JavaScriptHost.java:91)
      	at com.google.gwt.core.client.impl.Impl.apply(Impl.java)
      	at com.google.gwt.core.client.impl.Impl.entry0(Impl.java:242)
      	at sun.reflect.GeneratedMethodAccessor54.invoke(Unknown Source)
      	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      	at java.lang.reflect.Method.invoke(Method.java:606)
      	at com.google.gwt.dev.shell.MethodAdaptor.invoke(MethodAdaptor.java:103)
      	at com.google.gwt.dev.shell.MethodDispatch.invoke(MethodDispatch.java:71)
      	at com.google.gwt.dev.shell.OophmSessionHandler.invoke(OophmSessionHandler.java:172)
      	at com.google.gwt.dev.shell.BrowserChannelServer.reactToMessages(BrowserChannelServer.java:293)
      	at com.google.gwt.dev.shell.BrowserChannelServer.processConnection(BrowserChannelServer.java:547)
      	at com.google.gwt.dev.shell.BrowserChannelServer.run(BrowserChannelServer.java:364)
      	at java.lang.Thread.run(Thread.java:724)
      I've tried this in the following browsers: Chrome 33.0.1740.154 m, IE11, Firefox ESR 24.4.0

      This is a fairly large existing application, and while the majority of places are using the mechanism of creating new ListGridField items and calling setFields(), it looks like there are still a large number of places that call either getField or setFieldTitle. While I know that creating the fields is the best way to do this, my question was really if there was a simple solution that didn't require rewriting those bits of code.

      Comment


        #4
        Ah, sorry, we missed that you said getField() is returning null.

        In that case, since we don't have a general issue with getField() misbehaving, is there anything special about "enabledField"? Is it actually visible in the grid? Is it marked hidden="true" at the DataSource level, or has it had setHidden() called on it in the grid.

        Comment


          #5
          No, there is nothing special about the field. This happens with any field.

          It is not visible on the grid yet because it hasn't been drawn. This is all during construction.

          Comment


            #6
            We're taking a look. We'll follow up soon with more information

            Regards
            Isomorphic Software

            Comment


              #7
              The most likely cause of this issue is that your ListGrid hasn't yet "bound" to its dataSource.
              When you have a ListGrid with a specified DataSource, it goes through a binding step when any fields explicitly defined on the component are combined with fields defined on the DataSource to render out the final set of fields. After this has occurred a call to "getFields()" or "getField()" will pick up the "final" set of fields derived from both the DataSource fields and any fields set explicitly on the ListGrid.

              By default the binding happens on ListGrid.draw(), but you can also force this by an explicit call to setFields after the grid has been created.

              This has not changed between 4.0 and 4.1, but it is possible that in you app running against 4.0 you were somehow tripping this step before attempting to access the field and you no longer are.
              Regardless you should be able to fix this by calling:
              Code:
                  // Ensure the widget is created in JavaScript scope
                  if (!this.myListGrid.isCreated()) this.myListGrid.getOrCreateJsObj();
                  // Call setFields to force binding to the DataSource
                  this.myListGrid.setFields();
                  // Pick up the field object
                  final ListGridField fieldEnabled= this.myListGrid.getField( "enabledField" );
              Please let us know if this doesn't resolve the issue for you. We're taking a look at how to make this more intuitive for the future

              Regards
              Isomorphic Software

              Comment

              Working...
              X