Announcement

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

    UpdateCaches problem when adding records on a filtered TreeGrid

    Hello Community,
    I'm having some problems trying to add new records to a DataSource bound TreeGrid that is currently filtered.
    This problem is somewhat similar to another post that I've made some months ago (https://forums.smartclient.com/forum...arentsonfilter) and that has been successfully resolved.

    Here is my setup:
    • I have a TreeGrid that is bound to a custom DataSource.
    • The TreeGrid has filtering enabled and the filtering is made with the keepParentsOnFilter flag on.
    • The DataSource, for simplicity, returns the whole dataset in response to the first fetch operation. The dataset is a "John" root node and two child nodes ("Charles" and "Ford").
    • I have some external component that adds new data server side. The DataSource is informed of these changes and updates the TreeGrid through an updateCaches() call with an operation type of DSOperationType.ADD. I've mocked this behaviour with the "Add Chuck" and "Add Elvis" button in my showcase.
    The problem only happens when the TreeGrid is filtered. Hence, I now decide to filter by "Name" column putting the filter "ch" so that only "Charles" leaf node passes the filter. The parent "John" node is kept too thanks to the keepParentsOnFilter flag.

    Here is what I observe:
    1. Clicking "Add Chuck" button. The added node passes the filter. I see it on the (filtered) TreeGrid as expected.
    2. Clicking "Add Elvis" button. The added node does not pass the filter. I do not see it on the (filtered) TreeGrid as expected. However, if I now remove the filter, I do not see it either on the un-filtered TreeGrid. The added node is lost.
    I'm experiencing this problem using SmartGWT LGPL 4.1 (nightly build 2017-09-06). Every browser is affected.

    I've tried also to reproduce this behaviour on the latest SmartGWT 6.1 version (nightly build 2017-09-11). However, when I click the "Add X" buttons the browser complains that "this._sortValidRowsAndAddParents is not a function". This function is called by the addCacheData() function inside ResultTree.js. Hence, I cannot get past this point in the addCacheData() function to reproduce my main problem. (Looking at the similarities between the 4.1 and 6.1 versions of the addCacheData() function, however, I expect (but I'm not sure) that the same behaviour may happen).

    Thanks for any advice you can give me.

    TreeDataSource.java
    Code:
    import java.util.Collection;
    import java.util.HashMap;
    import java.util.Map;
    
    import com.smartgwt.client.data.DSRequest;
    import com.smartgwt.client.data.DSResponse;
    import com.smartgwt.client.data.DataSource;
    import com.smartgwt.client.data.fields.DataSourceTextField;
    import com.smartgwt.client.types.CriteriaPolicy;
    import com.smartgwt.client.types.DSOperationType;
    import com.smartgwt.client.types.DSProtocol;
    import com.smartgwt.client.widgets.tree.TreeNode;
    
    public class TreeDataSource extends DataSource {
    
        private final Map<String, TreeNode> dataset = new HashMap<String, TreeNode>();
    
        public TreeDataSource() {
            setClientOnly(true);
            setDataProtocol(DSProtocol.CLIENTCUSTOM);
            setCriteriaPolicy(CriteriaPolicy.DROPONCHANGE);
    
            DataSourceTextField idField = new DataSourceTextField("id");
            idField.setPrimaryKey(true);
            idField.setHidden(true);
    
            DataSourceTextField parentIdField = new DataSourceTextField("parentId");
            parentIdField.setForeignKey("id");
            parentIdField.setHidden(true);
    
            DataSourceTextField nameField = new DataSourceTextField("name");
            nameField.setCanFilter(true);
    
            setFields(idField, parentIdField, nameField);
    
            populateDataset();
        }
    
        protected void populateDataset() {
            TreeNode johnNode = new TreeNode();
            johnNode.setAttribute("id", "1");
            johnNode.setAttribute("parentId", (String) null);
            johnNode.setAttribute("name", "John");
            johnNode.setIsFolder(true);
            dataset.put("1", johnNode);
    
            TreeNode charlesNode = new TreeNode();
            charlesNode.setAttribute("id", "2");
            charlesNode.setAttribute("parentId", "1");
            charlesNode.setAttribute("name", "Charles");
            charlesNode.setIsFolder(false);
            dataset.put("2", charlesNode);
    
            TreeNode fordNode = new TreeNode();
            fordNode.setAttribute("id", "3");
            fordNode.setAttribute("parentId", "1");
            fordNode.setAttribute("name", "Ford");
            fordNode.setIsFolder(false);
            dataset.put("3", fordNode);
        }
    
        @Override
        protected Object transformRequest(final DSRequest dsRequest) {
            if (dsRequest.getOperationType() == DSOperationType.FETCH) {
                executeFetch(dsRequest);
            } else {
                throw new RuntimeException("Not supported operation type " + dsRequest.getOperationType().toString());
            }
            return dsRequest.getData();
        }
    
        protected void executeFetch(final DSRequest dsRequest) {
            String requestId = dsRequest.getRequestId();
            Collection<TreeNode> nodes = dataset.values();
            DSResponse response = new DSResponse();
            response.setData(nodes.toArray(new TreeNode[nodes.size()]));
            processResponse(requestId, response);
        }
    
        public void externalAddChuck() {
            TreeNode chuckNode = new TreeNode();
            chuckNode.setAttribute("id", "4");
            chuckNode.setAttribute("parentId", "1");
            chuckNode.setAttribute("name", "Chuck");
            chuckNode.setIsFolder(false);
            dataset.put("4", chuckNode);
    
            DSResponse response = new DSResponse();
            response.setData(chuckNode);
            response.setOperationType(DSOperationType.ADD);
            updateCaches(response);
        }
    
        public void externalAddElvis() {
            TreeNode elvisNode = new TreeNode();
            elvisNode.setAttribute("id", "5");
            elvisNode.setAttribute("parentId", "1");
            elvisNode.setAttribute("name", "Elvis");
            elvisNode.setIsFolder(false);
            dataset.put("5", elvisNode);
    
            DSResponse response = new DSResponse();
            response.setData(elvisNode);
            response.setOperationType(DSOperationType.ADD);
            updateCaches(response);
        }
    
    }

    TreeGridExample.java
    Code:
    import com.google.gwt.core.client.EntryPoint;
    import com.smartgwt.client.types.Alignment;
    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.layout.VLayout;
    import com.smartgwt.client.widgets.tree.TreeGrid;
    import com.smartgwt.client.widgets.tree.TreeGridField;
    
    public class TreeGridExample implements EntryPoint {
    
        @Override
        public void onModuleLoad() {
            final TreeDataSource treeDataSource = new TreeDataSource();
    
            TreeGrid personTree = new TreeGrid();
            personTree.setWidth(200);
            personTree.setHeight(400);
            personTree.setDataSource(treeDataSource);
            personTree.setAutoFetchData(true);
            personTree.setShowFilterEditor(true);
            personTree.setKeepParentsOnFilter(true);
            personTree.setFilterOnKeypress(true);
            TreeGridField nameField = new TreeGridField("name", "Name", 200);
            personTree.setFields(nameField);
    
            IButton chuckButton = new IButton("Add Chuck");
            chuckButton.addClickHandler(new ClickHandler() {
                @Override
                public void onClick(ClickEvent event) {
                    treeDataSource.externalAddChuck();
                }
            });
            chuckButton.setLayoutAlign(Alignment.CENTER);
    
            IButton elvisButton = new IButton("Add Elvis");
            elvisButton.addClickHandler(new ClickHandler() {
                @Override
                public void onClick(ClickEvent event) {
                    treeDataSource.externalAddElvis();
                }
            });
            elvisButton.setLayoutAlign(Alignment.CENTER);
    
            VLayout mainView = new VLayout(10);
            mainView.setHeight100();
            mainView.setWidth(200);
            mainView.addMember(personTree);
            mainView.addMember(chuckButton);
            mainView.addMember(elvisButton);
    
            mainView.draw();
        }
    
    }

    #2
    The JavaScript error has been fixed in SGWT 6.0p/SC 11.0p and newer releases (older releases don't have the issue) - this is in today's builds dated 2017-09-14.

    The problem of added nodes being dropped completely if they don't match the filter is a separate issue, and we've fixed it back to SGWT 6.0p/SC 11.0p - we don't plan to fix it in SGWT 4.1p/SC 9.1p. This change will be in the builds dated 2017-09-15 and beyond.

    Comment


      #3
      Hello again and thanks for the quick fix of both!

      May I kindly request a port back of the fix to version 4.1?
      We've been using SmartGWT in our project for years now, creating lots of interacting full SmartGWT applications. Migration to the newest version is in our roadmap but it will take plenty of time.

      It will be really helpful for us to have that fix back into 4.1.
      In either case, thank you.

      Comment


        #4
        We've ported the specific "node dropped" fix back to SGWT 4.1p/SC 9.1p, but in general we can't promise every fix will be ported back. It's in the builds dated 2017-09-17 and beyond.

        Comment

        Working...
        X