Announcement

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

    DataSource Fetches on Timer Erases UI Input

    Be sure your post includes:

    1. SmartClient Version: v8.3p_2013-02-09/PowerEdition Deployment (built 2013-02-09)

    2. Chrome 25.0.1364.172
    Firefox 18.0.2

    Ok, we are encountering a MAJOR UI/usability issue here.

    If not resolved, we may be moving away from Smart GWT in our next release.

    Issue:
    * We are trying to update some listgrids by refreshing them periodically with a timer.
    * We have noticed that when a user is trying to edit a listgrid record cell or another textbox-like item (including a listgrid filter or a dynamic form textfield), the item loses focus at the same interval as the timer firing.
    * When it loses focus it has the effect of either dropping user keystrokes or, WORSE YET, selecting and then deleting the value the user was typing in.

    I can repeatedly reproduce this issue on FF and Chrome in HOSTED and NON-HOSTED mode (Tomcat 7.0.34).

    Furthermore, the datasource doesn't even have to be the same datasource the user is editing and no UI changes/updates in our application code are even necessary.

    Here is sample code that added to any application will cause this horrific issue (note datasource below is from Smart GWT showcase samples)

    Code:
    new Timer() {
        @Override
        public void run() {
            DataSource.get("animals").fetchData(null, new DSCallback() {
                public void execute(DSResponse response, Object rawData, DSRequest request) {
                }
            });
        }
    }.scheduleRepeating(2000);
    As you can see, the code is doing nothing but just fetching "animals" data every 2 seconds.

    To make sure it wasn't something else in our App, I've modified the Smart GWT Showcase sample: builtinDS.

    File: BuiltInDS.java (note full file is attached)

    Here is all the code I modified in that file:
    Code:
    // EDITS START HERE at Line 179
            
            boundList.setShowFilterEditor(true);
            
            vStack.draw();
            
            startDeviceLayoutRefreshing();
        }
        
        private void startDeviceLayoutRefreshing() {
            new Timer() {
                @Override
                public void run() {
                    DataSource.get("animals").fetchData(null, new DSCallback() {
                        public void execute(DSResponse response, Object rawData, DSRequest request) {
                        }
                    });
                }
            }.scheduleRepeating(2000);
    	}
        
    // EDITS END HERE
    
        private void bindComponents(String dsName) {
            DataSource ds = DataSource.get(dsName);
            boundList.setDataSource(ds);
            boundViewer.setDataSource(ds);
            boundForm.setDataSource(ds);
            boundList.fetchData();
            newBtn.enable();
            saveBtn.disable();
        }
    }
    To observe this issue, while the app is running in FF or Chrome (in Chrome you can actually see the focus highlight appear and disappear every 2 seconds), as a user:
    1) Select the Animals datasource
    2) Try to enter a value above the Animal column in the filter editor box. You will notice if you type a longer search term at a reasonable speed your entries will keep disappearing as the item loses and then regains focus, clearing your selection
    3) Try to edit one of the cell values, say under the scientific name, by double-clicking the cell and then typing. You will notice you can't type more than a few characters before your entry is erased. Repeatedly.

    If you switch to the Office Supplies and try to edit a cell you will see the same behavior.

    The fact that NOTHING is being done to the UI in the timer code makes us believe that SOMETHING in the SmartGWT framework is causing a refresh or doing something to cause focus to be lost/re-gained repeatedly on datasource fetch.

    Has anyone else experienced this issue? Overcome it? Resolved it?

    Without the ability to refresh data AND allow users to edit listgrid cells, Smart GWT loses much of its appeal.
    Attached Files

    #2
    DataSource fetches are modal by default, so they block user action while they are being performed. Use rpcRequest.showPrompt to control this and turn it off for your background refreshes.

    Comment


      #3
      Originally posted by chimpeenuts View Post
      Be sure your post includes:

      1. SmartClient Version: v8.3p_2013-02-09/PowerEdition Deployment (built 2013-02-09)

      2. Chrome 25.0.1364.172
      Firefox 18.0.2

      Ok, we are encountering a MAJOR UI/usability issue here.

      If not resolved, we may be moving away from Smart GWT in our next release.

      Issue:
      * We are trying to update some listgrids by refreshing them periodically with a timer.
      * We have noticed that when a user is trying to edit a listgrid record cell or another textbox-like item (including a listgrid filter or a dynamic form textfield), the item loses focus at the same interval as the timer firing.
      * When it loses focus it has the effect of either dropping user keystrokes or, WORSE YET, selecting and then deleting the value the user was typing in.

      I can repeatedly reproduce this issue on FF and Chrome in HOSTED and NON-HOSTED mode (Tomcat 7.0.34).

      Furthermore, the datasource doesn't even have to be the same datasource the user is editing and no UI changes/updates in our application code are even necessary.

      Here is sample code that added to any application will cause this horrific issue (note datasource below is from Smart GWT showcase samples)

      Code:
      new Timer() {
          @Override
          public void run() {
              DataSource.get("animals").fetchData(null, new DSCallback() {
                  public void execute(DSResponse response, Object rawData, DSRequest request) {
                  }
              });
          }
      }.scheduleRepeating(2000);
      As you can see, the code is doing nothing but just fetching "animals" data every 2 seconds.

      To make sure it wasn't something else in our App, I've modified the Smart GWT Showcase sample: builtinDS.

      File: BuiltInDS.java (note full file is attached)

      Here is all the code I modified in that file:
      Code:
      // EDITS START HERE at Line 179
              
              boundList.setShowFilterEditor(true);
              
              vStack.draw();
              
              startDeviceLayoutRefreshing();
          }
          
          private void startDeviceLayoutRefreshing() {
              new Timer() {
                  @Override
                  public void run() {
                      DataSource.get("animals").fetchData(null, new DSCallback() {
                          public void execute(DSResponse response, Object rawData, DSRequest request) {
                          }
                      });
                  }
              }.scheduleRepeating(2000);
      	}
          
      // EDITS END HERE
      
          private void bindComponents(String dsName) {
              DataSource ds = DataSource.get(dsName);
              boundList.setDataSource(ds);
              boundViewer.setDataSource(ds);
              boundForm.setDataSource(ds);
              boundList.fetchData();
              newBtn.enable();
              saveBtn.disable();
          }
      }
      To observe this issue, while the app is running in FF or Chrome (in Chrome you can actually see the focus highlight appear and disappear every 2 seconds), as a user:
      1) Select the Animals datasource
      2) Try to enter a value above the Animal column in the filter editor box. You will notice if you type a longer search term at a reasonable speed your entries will keep disappearing as the item loses and then regains focus, clearing your selection
      3) Try to edit one of the cell values, say under the scientific name, by double-clicking the cell and then typing. You will notice you can't type more than a few characters before your entry is erased. Repeatedly.

      If you switch to the Office Supplies and try to edit a cell you will see the same behavior.

      The fact that NOTHING is being done to the UI in the timer code makes us believe that SOMETHING in the SmartGWT framework is causing a refresh or doing something to cause focus to be lost/re-gained repeatedly on datasource fetch.

      Has anyone else experienced this issue? Overcome it? Resolved it?

      Without the ability to refresh data AND allow users to edit listgrid cells, Smart GWT loses much of its appeal.
      This actually makes sense to me. I don't work for Isomorphic. I have seen data bound grids in .net do the same thing. There are several posts on this, try these https://www.google.com/search?q=smartgwt+datasource+auto+refresh&ie=UTF-8&oe=UTF-8&hl=en&client=safari

      Comment


        #4
        Originally posted by Isomorphic View Post
        DataSource fetches are modal by default, so they block user action while they are being performed. Use rpcRequest.showPrompt to control this and turn it off for your background refreshes.
        Ok.

        1) I tried doing this in the modified Showcase BuiltInDS Example BEFORE the timer ever starts: RPCManager.setShowPrompt(false)

        The issue still occurs.

        2) According tot he setShowPrompt documentation (quoted below), setShowPrompt is false by default so I shouldn't even be seeing this behavior:

        Code:
        If set to true, the RPCManager will block the UI with a modal dialog containing the text from RPCManager.defaultPrompt (or the per-RPCRequest override) until the RPC to the server completes.
        
        If set to false, the RPC happens transparently, allowing the user to continue interacting with the UI
        
        Parameters:
        showPrompt default is false
        So:
        [a] I'm either using RPCManager.setshowprompt incorrectly
        [b] setShowPrompt isn't actually working
        [c] Some other issue and/or bug is occurring

        Comment


          #5
          rpcRequest.showPrompt not RPCManager.showPrompt. This property has defaults at different levels - DataSource.showPrompt defaults to true.

          Comment


            #6
            Originally posted by bwilkins30 View Post
            This actually makes sense to me. I don't work for Isomorphic. I have seen data bound grids in .net do the same thing. There are several posts on this, try these https://www.google.com/search?q=smartgwt+datasource+auto+refresh&ie=UTF-8&oe=UTF-8&hl=en&client=safari
            Thanks for the reply. I've used datagrids in .net before and actually never had this issue (at least in WinForms and WPF). Not sure if you meant WebForms or asp.net.

            As for refreshing the datasource, that's not the issue. If you look at the code I posted, I'm getting this major UI issue WITHOUT even touching the datagrid or it's associated datasource. At first I thought my refreshing code was causing the UI focus to be lost, but my timer does NOTHING but call a datasource fetch command.

            Even after setting setShowPrompt to false as recommended above, the issue still persists.

            Since I've added about 9 lines to the SmartGWT Showcase example I imagine it should be trivial for Isomorphic to reproduce this issue.

            Unless, as I've written I'm using RPCManager.setShowPrompt incorrectly.

            Thanks for responding though =)

            Comment


              #7
              Originally posted by chimpeenuts View Post
              Thanks for the reply. I've used datagrids in .net before and actually never had this issue (at least in WinForms and WPF). Not sure if you meant WebForms or asp.net.

              As for refreshing the datasource, that's not the issue. If you look at the code I posted, I'm getting this major UI issue WITHOUT even touching the datagrid or it's associated datasource. At first I thought my refreshing code was causing the UI focus to be lost, but my timer does NOTHING but call a datasource fetch command.

              Even after setting setShowPrompt to false as recommended above, the issue still persists.

              Since I've added about 9 lines to the SmartGWT Showcase example I imagine it should be trivial for Isomorphic to reproduce this issue.

              Unless, as I've written I'm using RPCManager.setShowPrompt incorrectly.

              Thanks for responding though =)
              What's your setting for list grid.waitforsave?

              Comment


                #8
                Originally posted by Isomorphic View Post
                rpcRequest.showPrompt not RPCManager.showPrompt. This property has defaults at different levels - DataSource.showPrompt defaults to true.
                Ok.

                Yes, I see my error there. How do I set rpcRequest.setShowPrompt(false) in the sample code I posted above?

                I don't believe I can put it in the execute method because that callback happens AFTER the datasource has been fetched. Correct?

                Do I have to create a separate RPCRequest object and then use RPCManager.send(request)?

                If so, how do I tell RPCRequest to do a standard datasource fetch operation? Are there convenience methods to do this or do I have to figure out the data to send as well as the actual URL?

                Finally, according to the documentation rpcRequest.setShowPrompt's default is supposed to be RPCManager.setShowPrompt so if I set RPCManager to false, shouldn't all rpcRequests respect that?

                Code:
                Overrides RPCManager.showPrompt for this request only. If you're using queuing, note that if any of the requests in the queue specify showPrompt:true, then a prompt will be shown for the entire queue with the prompt text of the first request in the queue to specify a custom prompt if promptStyle is set to "dialog". If promptStyle is set to "cursor" for the request that specified showPrompt: true, then the entire queue uses the "cursor" style for the prompt.
                
                Parameters:
                showPrompt - showPrompt Default value is RPCManager.showPrompt

                Comment


                  #9
                  Back again to our first post now - use the requestProperties argument, which is part of all called that do DataSource operations. The type of the requestProperties argument is DSRequest, a subclass of RPCRequest.

                  Comment


                    #10
                    Originally posted by bwilkins30 View Post
                    What's your setting for list grid.waitforsave?
                    I don't have ListGrid.setWaitForSave set at all. It's not really an issue of the grid updating or waiting for grid to save before user finishes editing.

                    It's an issue with how Smart GWT handles UI updates during a standard datasource fetch operation.

                    If you look at my code above (unless there's some under-the-hood SmartGWT logic going on), in the Timer "run" method all I'm doing is a datasource.fetch call. I'm not updating a datagrid's resultset, calling updateCaches, calling refreshRow, calling refreshCell, calling redraw, calling markforRedraw, etc. I'm just accessing a datasource and telling it to get me all the data.

                    In my opinion this should have NO affect on the user UI. According to Isomorphic, ***ANY*** datasource fetch holds up the UI which seems odd as a default to me but I can see why you might want to prevent user from editing UI while fetching data.

                    The issue, however, is that it's not actually preventing me from editing. I can edit things (grid filter, form text box, grid cell) but the datasource fetch is forcing a focus lost/gain on the editable control and effectively erasing whatever I'd been typing.

                    If you have downloaded the Smart GWT libs and have the Samples showcase, you can easily throw the file attached above into the BuiltInDS example, run it in hosted mode, and following my steps above to see exactly what I'm talking about.

                    Comment


                      #11
                      Originally posted by Isomorphic View Post
                      Back again to our first post now - use the requestProperties argument, which is part of all called that do DataSource operations. The type of the requestProperties argument is DSRequest, a subclass of RPCRequest.
                      Praise the Lord! After several days of troubleshooting and trying to resolve this issue, WE HAVE a SOLUTION!

                      Yes, I forgot about passing a DSRequest as the 3rd parameter to a datasource fetch operation.

                      This indeed did solve my problem. My UI now doesn't "flicker".

                      My final Sample showcase code for others who may be interested:
                      Code:
                      new Timer() {
                          @Override
                          public void run() {
                              DSRequest request = new DSRequest();
                              request.setShowPrompt(false);
                              DataSource.get("animals").fetchData(null, new DSCallback() {
                                  public void execute(DSResponse response, Object rawData, DSRequest request) {
                                       // Do code here.
                                  }
                              }, request);
                          }
                      }.scheduleRepeating(2000);
                      NOTE above the empty DSRequest, with setShowPrompt to false and being passed in as **3rd** parameter to fetch data.

                      Full file is attached.

                      Thank you Isomorphic.

                      I think there may still be a bug/issue since setting RPCManager.setShowPrompt(false) clearly does not set all DSRequests to have false for that property. That would be a nice feature to have because although the solution above works, I now need to update dozens of fetchData calls instead of just updating one line of code.

                      Also, the whole power of using the built-in ds.xml files and datasources is they do the fetching behind the scenes. If they don't respect the global RPCManager.setShowPrompt setting, how am I going to have them NOT flicker UI focus without writing them all by hand?
                      Attached Files
                      Last edited by chimpeenuts; 14 Mar 2013, 17:28. Reason: Had incorrect code block.

                      Comment


                        #12
                        Originally posted by chimpeenuts View Post
                        I don't have ListGrid.setWaitForSave set at all. It's not really an issue of the grid updating or waiting for grid to save before user finishes editing.

                        It's an issue with how Smart GWT handles UI updates during a standard datasource fetch operation.

                        If you look at my code above (unless there's some under-the-hood SmartGWT logic going on), in the Timer "run" method all I'm doing is a datasource.fetch call. I'm not updating a datagrid's resultset, calling updateCaches, calling refreshRow, calling refreshCell, calling redraw, calling markforRedraw, etc. I'm just accessing a datasource and telling it to get me all the data.

                        In my opinion this should have NO affect on the user UI. According to Isomorphic, ***ANY*** datasource fetch holds up the UI which seems odd as a default to me but I can see why you might want to prevent user from editing UI while fetching data.

                        The issue, however, is that it's not actually preventing me from editing. I can edit things (grid filter, form text box, grid cell) but the datasource fetch is forcing a focus lost/gain on the editable control and effectively erasing whatever I'd been typing.

                        If you have downloaded the Smart GWT libs and have the Samples showcase, you can easily throw the file attached above into the BuiltInDS example, run it in hosted mode, and following my steps above to see exactly what I'm talking about.
                        It should send whatever has been typed in an update operation, so tha when it is fetched, everything else is updated. I can see how it is frustrating that the control loses focus. I am on my phone and trying to help since isomorphic does not always respond right away.

                        Comment


                          #13
                          Originally posted by bwilkins30 View Post
                          It should send whatever has been typed in an update operation, so tha when it is fetched, everything else is updated. I can see how it is frustrating that the control loses focus. I am on my phone and trying to help since isomorphic does not always respond right away.
                          Ah ok. I appreciate the help. Isomorphic actually was very quick to the rescue this time (thanks again Isomorphic...though it would be nice that RPCManager.setShowPrompt did work globally per documentation). And I see what you mean about updating grid. I will give that a shot in the future if I need to handle that case. Right now I was just trying to run a background timer that called datasource.fetch and have it not affect my user's UI experience.

                          Isomorphic's last post put me on the right trail and definitely helped...I wish there was a global configuration setting I could use...but I'll do the best I can with the tools i have.

                          Thanks for all the help...especially while mobile =)

                          Comment


                            #14
                            I think there may still be a bug/issue since setting RPCManager.setShowPrompt(false) clearly does not set all DSRequests to have false for that property. That would be a nice feature to have because although the solution above works, I now need to update dozens of fetchData calls instead of just updating one line of code.
                            I wish there was a global configuration setting I could use...but I'll do the best I can with the tools i have.
                            ... and back again to our second post:

                            rpcRequest.showPrompt not RPCManager.showPrompt. This property has defaults at different levels - DataSource.showPrompt defaults to true.
                            The default setting of true for DataSource.showPrompt is why all *DataSource* requests default to showing a prompt.

                            DataSource requests are a particular type of RPCRequest.

                            Your call to RPCManager.setShowPrompt(false) worked fine. It just did nothing, because that's already the default, and there's a different default for the (more specific) DataSource requests, again, controlled by DataSource.showPrompt.

                            Finally, setting DataSource.showPrompt to false by default is almost certainly a bad idea, unless you want to think through all of the interactions that might happen in the middle of a fetch or save that would lead to a bad result. You will end up pervasively adding checks to various event handlers to avoid having a Save button pressed twice, prevent further edits during a pending save, etc.

                            There are far fewer cases where you want non-blocking operations, and for those, you should set showPrompt:false on the specific call.

                            Comment


                              #15
                              Isomorphic -

                              Thanks for the more detailed response and explanation...I didn't realize there were different "levels" of requests as well as different "defaults" for showPrompt:

                              RPCManager
                              DataSource
                              DSRequest

                              Your post makes everything more clear. Your initial response, combined with my brain fog, just didn't click. As for defaulting DataSource.setShowPrompt to true, I now see the rationale and logic behind having that as a default setting. You are correct that most of the time the user should be prevented from doing things in the UI while the DataSource is updating.

                              Thank you for taking the time to resolve this issue!

                              Comment

                              Working...
                              X