Announcement

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

    Selecting all rows in a ListGrid when the complete data set is not loaded on client

    Hello,

    We use a DataSource that gets data from a pre-existing Oracle database. We display the data in a ListGrid in batches of 75 rows. This works fine for general scrolling and single row operations and saves a lot of load time as some of the ListGrids contain thousands of rows. But for some operations the users want to be able to apply an operation to all the rows. When you try to click the select all checkbox in the header row, you get a "Can't select that many records at once" hover. Is there a way to get control of this and let the user select the checkbox? We would be happy to do the actual operation on the backend. There currently doesn't seem to be a way to control this hover or get access to the checkbox so that we could put our own onChange handler on it.

    The customers have stated that having the select all functionality is a big deal to them and that they want it available no matter how many rows would be selected.

    What is the best way to deliver this functionality?

    We are using version SmartGWT 2.5.

    Thanks for any help,
    Brig

    #2
    We've tackled this before, and its much more complex than it appears, because of cases like what is supposed to happen when you select all but one by de-selecting a row after using select all.

    There are basically two approaches that make sense:

    1. Treat "Select All" as a special state, triggered externally to the grid and displays externally to the grid. When active, it disables the built-in ability to select/deselect individual rows (typically, just hides the checkbox column). In order to start selecting and de-selecting individual rows again, you need to leave the special "select all" state.

    2. Always track the selection on the server, even for individual rows, taking advantage of the ability to set a specific selectionProperty and have the server set it for newly loaded rows during load on demand. We've got an implementation of the client side of this already, which could be made a supported feature via Feature Sponsorship. This is obviously fairly resource intensive on the server - many more turnarounds even for small selections, large memory footprints while the user is editing very large selections.

    Comment


      #3
      Workaround

      We figured out a workaround for this. It is not pretty, but it seems to work.

      First you have to find the checkbox in the selection column and adjust it. You have to do this after the data has been loaded. Here is some non-pretty code that does it. What it does is look through the Canvas tree until it finds the hover for the checkbox. It then un-disables it, gets rid of the hover and puts a ClickHandler on it.

      Code:
              g.addDataArrivedHandler(new DataArrivedHandler() {
                  @Override
                  public void onDataArrived(DataArrivedEvent event) {
                      if (!isInitialPageLoad) {
                          gridPreferences.saveAll();
                      }
                      isInitialPageLoad = false;
                      recordCountLabel.setIcon(null);
                      recordCountLabel.setContents(grid.getTotalRows() + " records found");
                      final int sRow = event.getStartRow();
                      final int eRow = event.getEndRow();
                      if(allSelected) {
                          for(int llx = sRow; llx < eRow; llx++) {
                              g.selectRecord(llx);
                          }
                      }
      if(g instanceof ReportListGrid) {
      Canvas[] children = g.getChildren();
      for(Canvas c1 : children) {
          String s1 = c1.toString();
      //        Window.alert("child " + c1);
              Canvas[] ca2 = c1.getChildren();
              for(Canvas c3 : ca2) {
      //            Window.alert("grandchild " + c3.getScClassName() + " " + c3.getContents() + " " + c3.getTitle());
                  String ssx = c3.getTitle();
                  if(ssx != null && ssx.indexOf("batches") != -1) {
      //                Window.alert("found the hover");
                      c3.setCanHover(false);
                      c3.setDisabled(false);
                      c3.addClickHandler(new ClickHandler() {   
                          public void onClick(ClickEvent event) {
                              allSelected = !allSelected;
                              if(allSelected) {
      Window.alert("UUGA clickhandler totalrows=" + g.getTotalRows() + "sRow=" + sRow + " eRow=" + eRow);
                                  for(int llx = sRow; llx < eRow; llx++) {
                                      g.selectRecord(llx);
                                  }
                                  if(sRow != 0) {
                                      // this is to pick up all the rows already loaded
                                      for(int llx = 0; llx < g.getTotalRows(); llx++) {
                                          ListGridRecord glx = g.getRecord(llx);
                                          if(glx.getAttribute("hC") == null) {
                                              g.selectRecord(llx);
                                          }
                                      }                    
                                  }
      Window.alert("done selecting");
                              }
                      else {
      Window.alert("starting deselecting");
                          g.deselectAllRecords();
      Window.alert("finished deselecting");
                      }
                          }   
                      });     
                  }
              }
      }
      if(children == null) {
      Window.alert("children was null");
      }
      if(children.length == 0) {
      Window.alert("children was empty");
      }
      }
                  }
              });
      With this code, if you scroll after the select all is clicked, the newlly loaded code gets selected.

      Now we need code to handle when a user clicks on a menu item to go do something to all the selected rows. You have to deal with the situation that not all the rows may be loaded (in which case their ListGridRecords have javascript snippets in them) and the user may have unselected some rows manually. So we need to look through the grid to find rows that have had the selection turned off and make a list of them to pass to the server. This code is in the MenuItem click handler. The call to the server has been left off as it isn't especially germain.

      Code:
              bulkMenuItem.addClickHandler(new ClickHandler() {   
                  public void onClick(MenuItemClickEvent event) {
                      ListGridRecord[] selections = grid.getSelectedRecords();
                      if(selections == null) {
                          Window.alert("You clicked the menu item, selections is null");
                      }
                      else {
                          Window.alert("You clicked the menu item, selections.length=" + selections.length);
                      }
                      for(int llx = 0; llx < grid.getTotalRows(); llx++) {
                          ListGridRecord lgrx = grid.getRecord(llx);
                          if(lgrx.getAttribute("hC") == null) {
                              Map mx = lgrx.toMap();
                              Boolean sf = (Boolean)mx.get("_selection_8");
                              if(sf == null || !sf.booleanValue()) {
                              Window.alert("llx=" + llx + " lgrx=" + mx);
                              }
                          }
                      } 
                  }
              });
      The line with "hC" is critical. A row that has not been loaded yet has an attribute with key "hC" which has a snippet of Javascript as the value. If we see that, it is a row that has not been loaded yet and we can't process it normally.

      Comment


        #4
        Very hard to read this code (what's with the crazy indentation?) but is your hack here that if the user has selected all and then further modifies the selection, everything is de-selected?

        Otherwise you've got a big hack that doesn't appear to solve anything..

        Also, you don't need these crazy hacks even if the workaround approach made sense. ResultSet.rowIsLoaded() is a simple API for detecting whether a row is cached. You can access the first header via the listGrid.header autoChild without searching all children.

        Comment


          #5
          Without the looping code, how would we override select all settings?

          I understand what is being attempted here and need to do the same thing. The posted code works, but only when the tooltip is set because too many records would be selected.

          I need a more reliable way to find the checkbox and modify its behavior in this way. We will be handling all the ugly stuff like tracking when users unselect and unselect all and will be handling what gets sent to the server in various scenarios, but first we need to get a handle on the select all checkbox.

          Thoughts on how we can do this with SGWT 2.5?

          Thanks in advance!

          Comment

          Working...
          X