Announcement

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

    TreeGrid / DataSource hangs at second invoke

    I'm struggling with an issue that appeared in our (rather large) SmartGWT application after a SmartGWT library upgrade. We upgraded from one of the first SmartGWT 4.0 releases to a recent version (v9.0p_2015-08-12/LGPL Development Only (built 2015-08-12)). Before the upgrade we did not see this issue. Also tried SmartGWT version 5.0 which shows the same behavior. GWT is version 2.5.1.

    When running in Dev Mode everything works fine. However when compiling the code to JS and deploying the .war we see an issue with our TreeGrids: The very first time one is shown everything works fine, then after it has been destroyed and re-created it 'hangs' as if there are no records (The 'Loading..' message is displayed). This failure also happens when an ListGrid with DataSource has been shown previously. The log file shows both the "Destroying Treegrid" and "Destroying datasource" messages, so things seem to get cleaned up correctly. We use a TabSet to destroy (tab close) and re-create (tab open) the widget.

    It starts to get really tricky when trying to reproduce this issue. When I solely add a TabSet and the below code to the rootpanel and not initialize anything else, it works. Even destroying (tab close) and re-creating (tab open) works. However when the TreeGrid has been embedded into our application it only works once, and when created for a second time the loading hangs with the above message.

    Obviously I cannot post our whole application here, but it seems like something is influencing the behavior of the Treegrid. When another TreeGrid or ListGrid (both containing a datasource) have displayed the next instance of TreeGrid hangs. No further logging or exceptions (I use the UncaughtExceptionHandler) are shown either.

    ​Its a bit of a long shot, but does anybody have any clue what might cause this behavior?

    The used code is pretty much identical to the showcase example:
    Code:
        final TestDS dataSource = TestDS.getInstance();
        final TreeGrid treeGrid = new TreeGrid()
            {
            @Override
            public void destroy()
                {
                logger.info("Destroying Treegrid");
                super.destroy();
                dataSource.destroy();
                }
            };  
            treeGrid.setLoadDataOnDemand(false);  
            treeGrid.setWidth(500);  
            treeGrid.setHeight(400);  
            treeGrid.setDataSource(dataSource);  
            treeGrid.setNodeIcon("icons/16/person.png");  
            treeGrid.setFolderIcon("icons/16/person.png");  
            treeGrid.setAutoFetchData(true);  
      
            TreeGridField nameField = new TreeGridField("Name", 150);  
            TreeGridField jobField = new TreeGridField("Job", 150);  
            TreeGridField salaryField = new TreeGridField("Email");  
      
            treeGrid.setFields(nameField, jobField, salaryField);  
              
            treeGrid.addDataArrivedHandler(new DataArrivedHandler() {  
                public void onDataArrived(DataArrivedEvent event) {  
                    treeGrid.getData().openAll();  
                }  
            });  
              
        //load data
            TreeNode newRecord = new TreeNode();
        newRecord.setAttribute("EmployeeId", 2);
        newRecord.setAttribute("ReportsTo", 1);
        newRecord.setAttribute("Name", "Jan");
        
        TreeNode newRecord2 = new TreeNode();
        newRecord2.setAttribute("EmployeeId", 3);
        newRecord2.setAttribute("ReportsTo", 2);
        newRecord2.setAttribute("Name", "Piet");
    
        TreeNode newRecord3 = new TreeNode();
        newRecord3.setAttribute("EmployeeId", 4);
        newRecord3.setAttribute("ReportsTo", 3);
        newRecord3.setAttribute("Name", "Klaas");
        newRecord3.setAttribute("Job", "jobdescriptioooon");
        newRecord3.setAttribute("Email", "jan@ns.nl");
        
        dataSource.setCacheData(newRecord, newRecord2, newRecord3);
        
        return treeGrid;
    Code:
    public class TestDS extends DataSource
        {
        private Logger logger = Logger.getLogger("TestDS");
    
        public static TestDS getInstance()
        {
        return new TestDS();
        }
    
        public TestDS()
        {
        setTitleField("Name");
        DataSourceTextField nameField = new DataSourceTextField("Name",
                                    "Name",
                                    128);
    
        DataSourceIntegerField employeeIdField = new DataSourceIntegerField("EmployeeId",
                                            "Employee ID");
        employeeIdField.setPrimaryKey(true);
        employeeIdField.setRequired(true);
    
        DataSourceIntegerField reportsToField = new DataSourceIntegerField("ReportsTo",
                                           "Manager");
        reportsToField.setRequired(true);
        reportsToField.setForeignKey(getID() + ".EmployeeId");
        reportsToField.setRootValue("1");
    
        DataSourceTextField jobField = new DataSourceTextField("Job",
                                       "Title",
                                       128);
        DataSourceTextField emailField = new DataSourceTextField("Email",
                                     "Email",
                                     128);
    
        setFields(nameField,
              employeeIdField,
              reportsToField,
              jobField,
              emailField);
    
        setClientOnly(true);
        }
    
        @Override
        public void destroy()
        {
        logger.info("Destroying datasource");
        super.destroy();
        }
        }
    Last edited by Xandrios; 12 Jan 2016, 06:40.

    #2
    The very first time one is shown everything works fine, then after it has been destroyed and re-created it 'hangs' as if there are no records (The 'Loading..' message is displayed)
    From here, you start trying to figure out how to reproduce the issue. You skipped past the basics: are there messages in the Developer Console, including possibly a JavaScript error? Did a request go to the server (RPC tab)? If so, what was the response?

    Comment


      #3
      Thanks for your help, appreciate it!

      There were no Java or JS errors or exceptions around the creation of either the TreeGrid or Datasource. However, after a lot of trial&error I did find out that, at a totally different part of the application, an Form element was causing this behavior. What seemed to be happening is the following:

      - We create a popup with a login form
      - The form is submitted, and the popup is closed after successful login
      - We destroy the objects related to the popup; the form and the fields within the form
      - A validate() call is done on the form. This may be in error - not quite sure yet why/who calls this
      - The validation fails since the form fields have already been destroyed
      - At a totally different part of the application the loading of TreeGrid data fails like described in the OP

      By preventing the validation to take place when already destroyed, the issue was resolved.

      However it is strange that an error in form validation causes this behavior on the TreeGrid. I can imagine that validate() should not be called on a destroyed form, but I can also imagine that there should be a check in the validate() method to prevent other widget(s) to fail later on..

      Another thing that is strange that this behavior cannot be replicated in Dev Mode. This makes me believe that the Form validation is handled differently in Devmode than in compiled code. Could this be related to the SmartClient library underneath?

      Thanks!
      Last edited by Xandrios; 14 Jan 2016, 01:29.

      Comment


        #4
        It is definitely invalid to call validate() on a destroyed form. This should result in a relatively clear error in the Developer Console.

        No, there is no difference in how validation is done in Dev Mode vs compiled. In fact, there is essentially nothing in the SmartClient layer that is done differently in these two modes, because there's no need.

        Further, we can't see any plausible way in which calling validate() on a destroyed form would subsequently affect TreeGrid functionality. We suspect that instead, your application logic reacts to the failure to validate in a way that breaks the rest of your app, without any framework issue per se being involved.

        However if you narrow this down to something that looks like a framework issue, please do let us know.

        Comment

        Working...
        X