Announcement

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

    Tree.indexOf() and Tree.findIndex() are not working for databounded TreeGrid

    Hello,

    It appears that neither indexOf() or findIndex() methods work when the Tree is loaded from a DataSource. find() works just fine. The issue was observed using Chrome 39.0.2171.99 and Isomorphic SmartClient/SmartGWT Framework (v10.0p_2014-12-09/Enterprise Deployment 2014-12-09) in both development and compiled modes.

    Test case:
    1. BuiltinDS.java
    Code:
    package com.smartgwt.sample.client;
    
    import com.google.gwt.core.client.EntryPoint;
    import com.smartgwt.client.core.KeyIdentifier;
    import com.smartgwt.client.data.DataSource;
    import com.smartgwt.client.types.TreeModelType;
    import com.smartgwt.client.util.Page;
    import com.smartgwt.client.util.PageKeyHandler;
    import com.smartgwt.client.util.SC;
    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.grid.ListGrid;
    import com.smartgwt.client.widgets.layout.HLayout;
    import com.smartgwt.client.widgets.layout.VStack;
    import com.smartgwt.client.widgets.tree.Tree;
    import com.smartgwt.client.widgets.tree.TreeGrid;
    import com.smartgwt.client.widgets.tree.TreeGridField;
    import com.smartgwt.client.widgets.tree.TreeNode;
    
    /**
     * Entry point classes define <code>onModuleLoad()</code>.
     */
    public class BuiltInDS implements EntryPoint {
        private ListGrid boundList;
        
        /**
         * This is the entry point method.
         */
        public void onModuleLoad() {
            KeyIdentifier debugKey = new KeyIdentifier();
            debugKey.setCtrlKey(true);
            debugKey.setKeyName("D");
    
            Page.registerKey(debugKey, new PageKeyHandler() {
                public void execute(String keyName) {
                    SC.showConsole();
                }
            });
    
    
            VStack vStack = new VStack();
            vStack.setLeft(175);
            vStack.setTop(75);
            vStack.setWidth("70%");
            vStack.setMembersMargin(20);
            final TreeGrid employeeTreeGrid = new TreeGrid();  
            employeeTreeGrid.setWidth(500);  
            employeeTreeGrid.setHeight(400);  
            employeeTreeGrid.setFields(new TreeGridField("nodeTitle"));  
            employeeTreeGrid.setDataSource(DataSource.get("test_tree"));
            employeeTreeGrid.fetchData();
              
            vStack.addMember(employeeTreeGrid);
            
            HLayout hLayout = new HLayout(10);
            hLayout.setMembersMargin(10);
            hLayout.setHeight(22);
    
            IButton button = new IButton("Check");
            button.addClickHandler(new ClickHandler() {
    			@Override
    			public void onClick(ClickEvent event) {
    				for (TreeNode tnode : employeeTreeGrid.getData().getAllNodes()) {
    					SC.logWarn("Path:" + employeeTreeGrid.getData().getPath(tnode));
    				}
    				TreeNode node = employeeTreeGrid.getData().find("/1/2");
    				if (node != null) {
    					int index = employeeTreeGrid.getData().indexOf(node);
    					int findIndex = employeeTreeGrid.getData().findIndex("id", node.getAttribute("id"));
    					SC.say("indexOf returned " + index + " findIndex returned " + findIndex);
    				}
    			}
    		});
            hLayout.addMember(button);
            vStack.addMember(hLayout);
            
            vStack.draw();  
        }
    }
    2. test_tree.ds.xml:
    Code:
    <DataSource
        ID="test_tree"
    	serverType="sql"
    	tableName="test_tree"
    >
        <fields>
            <field name="id"  type="integer"  primaryKey="true"  required="true"/>
            <field name="nodeTitle" type="text"/>
            <field name="parent_id"     type="integer" foreignKey=".id"/>
        </fields>
    </DataSource>
    3. test tree table:
    Code:
    CREATE CACHED TABLE PUBLIC.TEST_TREE(ID INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 1) NOT NULL,nodeTitle VARCHAR_IGNORECASE(255),parent_id INTEGER DEFAULT NULL)
    insert INTO TEST_TREE VALUES(default,'Root', null)
    insert INTO TEST_TREE VALUES(default,'first level', 1)
    insert INTO TEST_TREE VALUES(default,'second level', 2)
    insert INTO TEST_TREE VALUES(default,'first level-2', 1)
    Start the application and click "Check" button. find() method correctly returns a TreeNode that can't be later located by indexOf() nor findIndex(). Both calls return -1.

    #2
    Do you really have ".id" (with a leading dot) as your foreignKey declaration? That's not valid (there should be no leading dot) and would lead to issues like this.

    Comment


      #3
      That was it. Thank you very much!

      Comment


        #4
        even stranger

        I have modified the test_tree.ds.xml as following:
        Code:
        <DataSource
            ID="test_tree"
        	serverType="sql"
        	tableName="test_tree"
        >
            <fields>
                <field name="id"  type="integer"  primaryKey="true"  required="true"/>
                <field name="nodeTitle" type="text"/>
                <field name="parent_id"     type="integer" foreignKey="test_tree.id"/>
            </fields>
        </DataSource>
        and added onDataArrived() to the tree to verify that all of the records can be identified:
        Code:
        employeeTreeGrid.addDataArrivedHandler(new DataArrivedHandler() {
         @Override
         public void onDataArrived(DataArrivedEvent event) {
          for (TreeNode node: employeeTreeGrid.getData().getAllNodes()) {
        	int recordIndex2 = employeeTreeGrid.getData().indexOf(node);
        	if (recordIndex2 < 0) {
        		SC.logWarn("index can't be determined for id:" + node.getAttribute("id"));
        	} else {
        		SC.logWarn("index was determined for id:" + node.getAttribute("id"));
        	}
          }
        }
        });
                employeeTreeGrid.fetchData();
        Much to my surprise the output indicated that only the first record index was successfully determined:
        Code:
        WARN:Log:index was determined for id:1
        WARN:Log:index can't be determined for id:2
        WARN:Log:index can't be determined for id:3
        WARN:Log:index can't be determined for id:4
        Does this sound like the expected behavior?

        Comment


          #5
          indexOf returns the node's index in the list of the currently visible records. Since, right after loading the tree, only root is visible, what you're seeing is what you should expect.

          Comment


            #6
            Thank you for the explanation. That makes sense now. So, we don't even have to call refreshRow() if the row is not visible, right? Our scenario involves 2 separate DataSources. First is the tree data and the second one contains the path in the tree and the node status. The first DataSource is tracked by the TreeGrid where's the second one is tracked by a ResultSet, so both can receive updates independently. Once the data arrives for either DataSource we set the node icons based on the tree data plus the status data (if available for the given path). What would be the best way to ensure that all the affected rows are refreshed?

            Comment


              #7
              Right, you do not need to call refreshRow() for a row that's been updated but isn't visible.

              A good way to check if a row is visible is to call indexOf() and see if it returns -1 :)

              However just a note that this kind of work is not normally done manually. If you have updates to apply that came in through something other than the DataSource layer, use DataSource.updateCaches() to broadcast such changes to the DataSource and to allow components that might have caches of the affected record.

              Comment

              Working...
              X