Announcement

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

    Problems while using FieldValueExtractor to extract isFolder property for TreeGrid

    I'm having trouble displaying nodes in the TreeGrid depending on the logical 'type' of the node (as returned by the rest datasource). I tried a few approaches (using latest nightly, gwt 2.1.1):

    1. Setting the isFolder for the TreeGrid's dataArrived event:
    Code:
    record.setAttribute("CONTAINER".equals(record.getAttribute("type"))
    This works for the initial display, but if I modify the node to another type, the tree grid doesn't change the type of the node, at least visually, as the event doesn't fire for updates.

    2. Using FieldValueExtractor to calculate the value of the isFolder flag. This causes issues if I specify the isFolder field as DataSourceBooleanField (isBoolean validator fails), before it even hits the extractor, I assume because the property is not available in the recordset returned from the serverside.
    This also had unexpected side effects, firefox would just hang there if I returned a boolean true/false from the DataSourceTextField field value extractor, and would work fine in chrome. Returning a string "true"/"false" in this case ended up making all nodes look like folders.

    Code:
            DataSourceField isFolder = new DataSourceTextField("isFolder", "Is container");
             isFolder.setFieldValueExtractor(new FieldValueExtractor() {
                 @Override
                 public Object execute(Object record, Object value, DataSourceField field, String fieldName) {
                     return  ("CONTAINER".equals((new Record((JavaScriptObject) record)).getAttribute("type")));
                 }
             });
        }
    3. The closest I got to the expected functionality, was using DataSourceTextField, and returning "1" for folders and null for leaves. This changes the icon to a folder when type is changed to a CONTAINER, but does not change it back to a leaf icon when the node type is changed to a different type (and it has no children). I
    Code:
            DataSourceField isFolder = new DataSourceTextField("isFolder", "Is container");
             isFolder.setFieldValueExtractor(new FieldValueExtractor() {
                 @Override
                 public Object execute(Object record, Object value, DataSourceField field, String fieldName) {
                     return  ("CONTAINER".equals((new Record((JavaScriptObject) record)).getAttribute("type")))?"1":null;
                 }
             });
    and hooking the dataArrived event to introduce a dataChanged event on the treeGrid.getTree();
    Code:
    treeGrid.addDataArrivedHandler(new DataArrivedHandler() {
        @Override
        public void onDataArrived(DataArrivedEvent event) {
            treeGrid.getTree().addDataChangedHandler(new DataChangedHandler() {
                @Override
                public void onDataChanged(DataChangedEvent event) {
                    for (TreeNode node : treeGrid.getTree().getAllNodes()) {
                        node.setAttribute("isFolder", "CONTAINER".equals(node.getAttribute("type")));
                    }
    
                }
            });
        }
    });
    This looks like a terrible hack to me. What would be the smartgwt way to achieve this functionality?

    regards,
    Andrius J.

    #2
    If you plan to extract a value of type boolean, the field should be of type "boolean". This seems to explain most of your results - if you're still having trouble explain the remaining problem.

    Comment


      #3
      Ok, let's reiterate then. My rest datasource returns the following (not sure how to simulate it using the local data source to simplify the testcase, my serverside is fairly heavy setup-wise), this is taken from the debug console:

      Code:
      18:55:39.464:XRP6:DEBUG:xmlBinding:categories:Raw response data: {
          "response":{
              "totalRows":2, 
              "status":0, 
              "startRow":0, 
              "endRow":2, 
              "data":[
                  {
                      "description":"ccc", 
                      "status":"ACTIVE", 
                      "position":0, 
                      "parentId":"ecom.category-10", 
                      "title":"Built systems", 
                      "_id":"ecom.category-6", 
                      "_rev":"70-22fa16463022b52ab892dde80d1814bc"
                  }, 
                  {
                      "description":"my root", 
                      "status":"ACTIVE", 
                      "position":0, 
                      "parentId":"", 
                      "title":"ščęėčęėčęė", 
                      "defaultProductType":"ecom.ptype-5", 
                      "_id":"ecom.category-10", 
                      "_rev":"31-abdada6c69326beec494f586b8c68d4c"
                  }
              ]
          }
      }
      18:55:39.469:XRP6:INFO:xmlBinding:categories:JSON recordXPath: '/response/data', selected: Array[2]
      Then, I use a trivial list grid with rest datasource:

      Code:
      public class AjaxElementsDemo implements EntryPoint {
          private static final String CATEGORIES = "categories";
      
          public static DataSource createCategoryDS() {
              RestDataSource restDataSource = new RestDataSource();
              restDataSource.setID(CATEGORIES);
              restDataSource.setDataFormat(DSDataFormat.JSON);
              DataSourceTextField idField = new DataSourceTextField("_id", "ID");
              idField.setPrimaryKey(true);
              idField.setCanEdit(false);
              OperationBinding fetch = new OperationBinding();
              fetch.setOperationType(DSOperationType.FETCH);
              fetch.setDataProtocol(DSProtocol.POSTPARAMS);
              restDataSource.setOperationBindings(fetch);
              restDataSource.setFetchDataURL("/" + restDataSource.getID() + "/fetch.do");
              restDataSource.setFields(idField);
      
              DataSourceTextField parentCategoryId = new DataSourceTextField("parentId", "Parent category");
      
              parentCategoryId.setForeignKey(CATEGORIES + "._id");
              parentCategoryId.setRootValue((String) null);
      
              DataSourceTextField title = new DataSourceTextField("title", "Title");
              DataSourceBooleanField isFolder = new DataSourceBooleanField("isFolder", "Is folder");
      
              isFolder.setFieldValueExtractor(new FieldValueExtractor() {
                  public Object execute(Object record, Object value, DataSourceField field, String fieldName) {
                      return true;
                  }
              });
              restDataSource.addField(title);
              restDataSource.addField(parentCategoryId);
              restDataSource.addField(isFolder);
              return restDataSource;
          }
      
          public void onModuleLoad() {
              final TreeGrid grid = new TreeGrid();
              grid.setLoadDataOnDemand(false);
              grid.setWidth("800px");
              grid.setHeight("2000px");
              grid.setDataSource(createCategoryDS());
              grid.setAutoFetchData(true);
              grid.setUseAllDataSourceFields(true);
              grid.draw();
          }
      }
      In firefox 3.6.13, when debugging, I hit the first call to FieldValueExtractor, proceed to return true, and it stops right there. No exceptions, neither in the gwt development console, nor debug console. The loading icon keeps spinning.
      In chrome 8 and 9-beta,the list loads correctly, and actually sets the isFolder to true (child category gets the folder icon).

      Let me know if you need any more details. Or am I misunderstanding some concepts about how this should work?

      regards,
      Andrius J.

      Comment


        #4
        You've never mentioned your SmartGWT version (always post this).

        We've got a number of test cases of FieldValueExtractor similar to yours that are working fine - try taking just your code sample, and running in SmartGWT 2.4 with a RestDataSource set up to point at the provided JSON response (as a file). If you're still seeing an issue there, that's a valid test case and we'll take a look.

        Comment


          #5
          smartgwt version is the nightly build of 23rd of january, but I've been seeing the same behavior with 2.4.

          Code:
          restDataSource.setFetchDataURL("/sample.json");
          and the sample.json has this:
          Code:
          {
              "response":{
                  "totalRows":2, 
                  "status":0, 
                  "startRow":0, 
                  "endRow":2, 
                  "data":[
                      {
                          "description":"ccc", 
                          "status":"ACTIVE", 
                          "position":0, 
                          "parentId":"ecom.category-10", 
                          "title":"Built systems", 
                          "_id":"ecom.category-6", 
                          "_rev":"70-22fa16463022b52ab892dde80d1814bc"
                      }, 
                      {
                          "description":"my root", 
                          "status":"ACTIVE", 
                          "position":0, 
                          "parentId":"", 
                          "title":"Root category", 
                          "defaultProductType":"ecom.ptype-5", 
                          "_id":"ecom.category-10", 
                          "_rev":"31-abdada6c69326beec494f586b8c68d4c"
                      }
                  ]
              }
          }

          Comment


            #6
            BTW, seeing the same behavior with the ListGrid too, so this is not TreeGrid specific. Attaching sc.console.log, just in case.


            regards,
            Andrius J.

            Comment


              #7
              We've managed to reproduce this issue and have fixed it in our mainline code base. The fix will be present in the next nightly build (Jan 28)

              Let us know if you continue to have problems with it!

              Thanks
              Isomorphic Software

              Comment


                #8
                I've seen the commits r1615-r1617, and assumed those are responsible for this fix, and built the version from the svn. This doesn't seem to fix the problem.

                This behavior is also affecting IE8, and Chrome 8 latest is complaining about the isBoolean validator upon each FieldValueExtractor.execute() call:

                Code:
                ERROR: 16:23:32.728:XRP1:WARN:RestDataSource:categories:categories.isFolder: value: true failed on validator: {type: "isBoolean",
                typeCastValidator: true,
                _generated: true,
                stopIfFalse: true,
                defaultErrorMessage: "Must be a true/false value.",
                resultingValue: true}. com.smartgwt.client.core.JsObject$SGWT_WARN: 16:23:32.728:XRP1:WARN:RestDataSource:categories:categories.isFolder: value: true failed on validator: {type: "isBoolean",
                typeCastValidator: true,
                _generated: true,
                stopIfFalse: true,
                defaultErrorMessage: "Must be a true/false value.",
                resultingValue: true}
                	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
                	at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
                	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
                	at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
                	at com.google.gwt.dev.shell.MethodAdaptor.invoke(MethodAdaptor.java:105)
                	at com.google.gwt.dev.shell.MethodDispatch.invoke(MethodDispatch.java:71)
                	at com.google.gwt.dev.shell.OophmSessionHandler.invoke(OophmSessionHandler.java:157)
                	at com.google.gwt.dev.shell.BrowserChannelServer.reactToMessages(BrowserChannelServer.java:281)
                	at com.google.gwt.dev.shell.BrowserChannelServer.processConnection(BrowserChannelServer.java:531)
                	at com.google.gwt.dev.shell.BrowserChannelServer.run(BrowserChannelServer.java:352)
                	at java.lang.Thread.run(Thread.java:619)
                Any advice would be appreciated. Of course this may not be relevant if you have some special ingredient in your nightly builds that I didn't have :)

                regards,
                Andrius J.

                Comment


                  #9
                  Grab the latest from smartclient.com/builds to get any overnight change. SVN commits happen on milestones (frequent, but not overnight).

                  Comment


                    #10
                    Ok, just checked it out. Works for Firefox, chrome complaints are gone, IE8 complains though:

                    Code:
                    Webpage error details
                    
                    User Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; InfoPath.2)
                    Timestamp: Fri, 28 Jan 2011 16:48:13 UTC
                    
                    
                    Message: 'undefined' is null or not an object
                    Line: 406
                    Char: 245
                    Code: 0
                    URI: http://192.168.1.71:8080/ajaxelements/sc/modules/ISC_DataBinding.js
                    and the devmode output has this:

                    Code:
                    ERROR: 18:47:37.841:XRP9:WARN:Log:Error:
                    	''undefined' is null or not an object'
                    	in http://192.168.1.71:8080/ajaxelements/sc/modules/ISC_DataBinding.js
                    	at line 406
                        DataSource.validateJSONRecord(_1=>undef)
                        DataSource.recordsFromObjects(_1=>Array[4])
                        DataSource.$377(_1=>Obj, _2=>Array[4], _3=>Obj)
                        DataSource.$379(rpcResponse=>Obj, jsonText=>"{response: {totalRows:3,    status:0,sta..."[536], rpcRequest=>Obj)
                        [c]Class.fireCallback(_1=>Obj, _2=>"rpcResponse,data,rpcRequest", _3=>Array[3], _4=>[RestDataSource ID:categories], _5=>undef) on [Class RPCManager]
                        Class.fireCallback(_1=>Obj, _2=>"rpcResponse,data,rpcRequest", _3=>Array[3], _4=>undef)
                        [c]RPCManager.__fireReplyCallback(_1=>Obj, _2=>Obj, _3=>Obj, _4=>"{response: {totalRows:3,    status:0,sta..."[536])
                        [c]RPCManager.fireReplyCallbacks(_1=>Obj, _2=>Obj)
                        [c]RPCManager.performOperationReply(_1=>Obj, _2=>Obj)
                        [c]RPCManager.$39d(_1=>0)
                        [c]RPCManager.performTransactionReply(_1=>0, _2=>"{response: {totalRows:3,    status:0,sta..."[536], _3=>undef)
                        callback(transactionNum=>0, results=>Obj, wd=>undef)
                            "isc.RPCManager.performTransactionReply(transactionNum,results,wd)"
                        ** recursed on [c]Class.fireCallback
                    . com.smartgwt.client.core.JsObject$SGWT_WARN: 18:47:37.841:XRP9:WARN:Log:Error:
                    	''undefined' is null or not an object'
                    	in http://192.168.1.71:8080/ajaxelements/sc/modules/ISC_DataBinding.js
                    	at line 406
                        DataSource.validateJSONRecord(_1=>undef)
                        DataSource.recordsFromObjects(_1=>Array[4])
                        DataSource.$377(_1=>Obj, _2=>Array[4], _3=>Obj)
                        DataSource.$379(rpcResponse=>Obj, jsonText=>"{response: {totalRows:3,    status:0,sta..."[536], rpcRequest=>Obj)
                        [c]Class.fireCallback(_1=>Obj, _2=>"rpcResponse,data,rpcRequest", _3=>Array[3], _4=>[RestDataSource ID:categories], _5=>undef) on [Class RPCManager]
                        Class.fireCallback(_1=>Obj, _2=>"rpcResponse,data,rpcRequest", _3=>Array[3], _4=>undef)
                        [c]RPCManager.__fireReplyCallback(_1=>Obj, _2=>Obj, _3=>Obj, _4=>"{response: {totalRows:3,    status:0,sta..."[536])
                        [c]RPCManager.fireReplyCallbacks(_1=>Obj, _2=>Obj)
                        [c]RPCManager.performOperationReply(_1=>Obj, _2=>Obj)
                        [c]RPCManager.$39d(_1=>0)
                        [c]RPCManager.performTransactionReply(_1=>0, _2=>"{response: {totalRows:3,    status:0,sta..."[536], _3=>undef)
                        callback(transactionNum=>0, results=>Obj, wd=>undef)
                            "isc.RPCManager.performTransactionReply(transactionNum,results,wd)"
                        ** recursed on [c]Class.fireCallback
                    	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
                    	at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
                    	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
                    	at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
                    	at com.google.gwt.dev.shell.MethodAdaptor.invoke(MethodAdaptor.java:105)
                    	at com.google.gwt.dev.shell.MethodDispatch.invoke(MethodDispatch.java:71)
                    	at com.google.gwt.dev.shell.OophmSessionHandler.invoke(OophmSessionHandler.java:157)
                    	at com.google.gwt.dev.shell.BrowserChannelServer.reactToMessages(BrowserChannelServer.java:281)
                    	at com.google.gwt.dev.shell.BrowserChannelServer.processConnection(BrowserChannelServer.java:531)
                    	at com.google.gwt.dev.shell.BrowserChannelServer.run(BrowserChannelServer.java:352)
                    	at java.lang.Thread.run(Thread.java:619)

                    Comment


                      #11
                      You've got a null entry in your JSON "data" Array.

                      Comment


                        #12
                        That was indeed the case - while FF and CR handled the data :[{rec1}, {rec2},] just fine, IE didn't like the extra comma in the end (I knew it was there, was just too lazy to fix it, since it didn't seem to cause any problems).

                        Case closed.

                        regards,
                        Andrius J.

                        Comment

                        Working...
                        X