Announcement

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

    ListGrid groupOpen/Closed best practice

    Hi Isomorphic,

    I have a ListGrid, thats grouped by a Field. What I want to achieve is the following:

    1. The ListGrid starts with GroupStartOpen.NONE, so all groups are collapsed. Groups open total: 0
    2. The User opens one group. Groups open total: 1
    3. The User opens another Group, but now the former opened Group must collapse Groups open total: 1

    A maximum of one group may be open.


    Setup: SmartClient Version: v12.0p_2018-09-04/PowerEdition Deployment (built 2018-09-04)
    Browser : Chrome

    I tried this, to get the functionality:


    Code:
    package com.smartgwt.sample.client;
    
    import com.google.gwt.core.client.EntryPoint;
    import com.smartgwt.client.Version;
    import com.smartgwt.client.core.KeyIdentifier;
    import com.smartgwt.client.data.SortSpecifier;
    import com.smartgwt.client.types.GroupStartOpen;
    import com.smartgwt.client.types.SelectionStyle;
    import com.smartgwt.client.types.SortDirection;
    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.Window;
    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.grid.ListGridField;
    import com.smartgwt.client.widgets.grid.events.CellClickEvent;
    import com.smartgwt.client.widgets.grid.events.CellClickHandler;
    import com.smartgwt.client.widgets.layout.VLayout;
    import com.smartgwt.client.widgets.tree.Tree;
    import com.smartgwt.client.widgets.tree.TreeNode;
    
    public class BuiltInDS extends VLayout implements EntryPoint {
        private IButton recreateBtn;
        private final String fakeLGFName = "fakeLGFName";
    
        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();
                }
            });
    
            setWidth100();
            setHeight100();
    
            recreateBtn = new IButton("Recreate");
            recreateBtn.addClickHandler(new ClickHandler() {
                @Override
                public void onClick(ClickEvent event) {
                    new MyWindow().show();
                }
            });
            addMember(recreateBtn);
            new MyWindow().show();
            draw();
        }
    
        private class MyWindow extends Window {
            public MyWindow() {
                setWidth(400);
                setHeight(600);
                setMembersMargin(0);
                setModalMaskOpacity(70);
                setTitle(" (" + Version.getVersion() + "/" + Version.getSCVersionNumber() + ")");
                SC.logWarn(" (" + Version.getVersion() + "/" + Version.getSCVersionNumber() + ")");
                setShowMinimizeButton(false);
                // setIsModal(true);
                // setShowModalMask(true);
                centerInPage();
    
                VLayout vL = new VLayout();
    
                // Img svgImg = new Img("http://127.0.0.1:8888/builtinds/tools/images/kiwi.svg", 100, 100);
                ListGrid lg = new ListGrid() {
                    {
                        setSelectionType(SelectionStyle.SINGLE);
                        setVirtualScrolling(true);
                        setShowRecordComponents(true);
                        setShowRecordComponentsByCell(true);
                        // Records becomes unreadable every next click in 12.0. version, we don't expect many record so this is fine solution.
                        // setRecordComponentPoolingMode(RecordComponentPoolingMode.RECYCLE);
                        setPoolComponentsPerColumn(true);
                        setFixedRecordHeights(true);
                        setRecordComponentHeight(56);
                        setCanSort(false);
                        setCanPickFields(false);
                        setCanResizeFields(false);
                        setCanAutoFitFields(false);
                        setCanGroupBy(false);
    
                        setAutoFetchData(false);
                        setDataSource("animals");
    
                        ListGridField scientificNameLGF = new ListGridField(fakeLGFName);
                        ListGridField lifeSpanLGF = new ListGridField("lifeSpan");
                        ListGridField endangered = new ListGridField("status");
                        endangered.setHidden(true);
                        lifeSpanLGF.setCanEdit(true);
    
                        setFields(endangered, scientificNameLGF, lifeSpanLGF);
    
                        setGroupByField(endangered.getName());
                        setGroupStartOpen(GroupStartOpen.NONE);
    
                        setSort(new SortSpecifier[] { new SortSpecifier("lifeSpan", SortDirection.DESCENDING) });
    
                        fetchData();
    
                        addCellClickHandler(new CellClickHandler() {
    
                            @Override
                            public void onCellClick(CellClickEvent event) {
                                Tree a = getGroupTree();
                                boolean changedOpen = true;
                                while (changedOpen) {
                                    changedOpen = false;
                                    for (TreeNode n : a.getAllNodes()) {
                                        if (n.getAttribute("groupName") != null && n.getAttribute("groupName").equals("status")
                                                && n.getAttribute("singleCellValue") != null) {
                                            SC.logWarn(event.getRecord().getAttribute("singleCellValue"));
                                            if (!n.getAttribute("singleCellValue").equals(event.getRecord().getAttribute("singleCellValue"))) {
                                                if (a.isOpen(n)) {
                                                    a.closeFolder(n);
                                                    changedOpen = true;
                                                }
                                            } else {
                                                if (!a.isOpen(n)) {
                                                    a.openFolder(n);
                                                    changedOpen = true;
                                                }
                                            }
                                        }
                                    }
                                }
                                event.cancel();
                            }
                        });
                    }
    
                };
    
                vL.addMembers(lg);
    
                addItem(vL);
            }
        }
    }
    Unfortunately, this doesn´t work, its result is that all groups are colapsed. Can you please give some advice?

    Regarding to this post, https://forums.smartclient.com/forum...groupstartopen
    a Handler for the open/closed state of the groups would be nice.

    Kind Regards
    Last edited by Developer12145; 19 Sep 2018, 05:32.

    #2
    It's not clear why you're traversing the tree or what you're doing with singleCellValue - you can instead identify group nodes using isGroupNode() if you need to. Instead of traversing the whole tree, just hold onto to the last opened group node and close it if the click is on a new group node.

    Comment


      #3
      Thanks for the quick response! I tried your suggestion with the result, that it works perfectly fine if I start at the last group node, from bottom to top, but the other way around it only closes the former open group, but does not open the new one, please see the attached recording.

      Click image for larger version

Name:	GroupByIssue.gif
Views:	85
Size:	468.8 KB
ID:	255163


      Here is my code:

      Code:
      package com.smartgwt.sample.client;
      
      import com.google.gwt.core.client.EntryPoint;
      import com.smartgwt.client.Version;
      import com.smartgwt.client.core.KeyIdentifier;
      import com.smartgwt.client.data.SortSpecifier;
      import com.smartgwt.client.types.GroupStartOpen;
      import com.smartgwt.client.types.SelectionStyle;
      import com.smartgwt.client.types.SortDirection;
      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.Window;
      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.grid.ListGridField;
      import com.smartgwt.client.widgets.grid.ListGridRecord;
      import com.smartgwt.client.widgets.grid.events.CellClickEvent;
      import com.smartgwt.client.widgets.grid.events.CellClickHandler;
      import com.smartgwt.client.widgets.layout.VLayout;
      
      public class BuiltInDS extends VLayout implements EntryPoint {
          private IButton recreateBtn;
          private final String fakeLGFName = "fakeLGFName";
          ListGridRecord currentGroupNodeOpen = null;
      
          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();
                  }
              });
      
              setWidth100();
              setHeight100();
      
              recreateBtn = new IButton("Recreate");
              recreateBtn.addClickHandler(new ClickHandler() {
                  @Override
                  public void onClick(ClickEvent event) {
                      new MyWindow().show();
                  }
              });
              addMember(recreateBtn);
              new MyWindow().show();
              draw();
          }
      
          private class MyWindow extends Window {
              ListGrid lg;
      
              public MyWindow() {
                  setWidth(800);
                  setHeight(800);
                  setMembersMargin(0);
                  setModalMaskOpacity(70);
                  setTitle(" (" + Version.getVersion() + "/" + Version.getSCVersionNumber() + ")");
                  SC.logWarn(" (" + Version.getVersion() + "/" + Version.getSCVersionNumber() + ")");
                  setShowMinimizeButton(false);
                  // setIsModal(true);
                  // setShowModalMask(true);
                  centerInPage();
      
                  VLayout vL = new VLayout();
      
                  // Img svgImg = new Img("http://127.0.0.1:8888/builtinds/tools/images/kiwi.svg", 100, 100);
                  lg = new ListGrid() {
                      {
                          setSelectionType(SelectionStyle.SINGLE);
                          setVirtualScrolling(true);
                          setShowRecordComponents(true);
                          setShowRecordComponentsByCell(true);
                          // Records becomes unreadable every next click in 12.0. version, we don't expect many record so this is fine solution.
                          // setRecordComponentPoolingMode(RecordComponentPoolingMode.RECYCLE);
                          setPoolComponentsPerColumn(true);
                          setFixedRecordHeights(true);
                          setRecordComponentHeight(56);
                          setCanSort(false);
                          setCanPickFields(false);
                          setCanResizeFields(false);
                          setCanAutoFitFields(false);
                          setCanGroupBy(false);
      
                          setAutoFetchData(false);
                          setDataSource("animals");
      
                          ListGridField scientificNameLGF = new ListGridField(fakeLGFName);
                          ListGridField lifeSpanLGF = new ListGridField("lifeSpan");
                          ListGridField endangered = new ListGridField("status");
                          endangered.setHidden(true);
                          lifeSpanLGF.setCanEdit(true);
      
                          setFields(endangered, scientificNameLGF, lifeSpanLGF);
      
                          setGroupByField(endangered.getName());
                          setGroupStartOpen(GroupStartOpen.NONE);
      
                          setSort(new SortSpecifier[] { new SortSpecifier("lifeSpan", SortDirection.DESCENDING) });
      
                          fetchData();
      
                      }
      
                  };
      
                  lg.addCellClickHandler(new CellClickHandler() {
      
                      @Override
                      public void onCellClick(CellClickEvent event) {
                          // TODO Auto-generated method stub
                          if (lg.isGroupNode(event.getRecord())) {
      
                              if (currentGroupNodeOpen == null) {
                                  lg.getGroupTree().closeAll();
                                  currentGroupNodeOpen = event.getRecord();
                              } else if (currentGroupNodeOpen != null && !currentGroupNodeOpen.equals(event.getRecord())) {
                                  boolean hasclosed = lg.closeGroup(currentGroupNodeOpen);
                                  currentGroupNodeOpen = event.getRecord();
                              } else if (currentGroupNodeOpen != null && currentGroupNodeOpen.equals(event.getRecord())) {
                                  currentGroupNodeOpen = null;
                              }
      
                          }
                      }
      
                  });
                  vL.addMembers(lg);
      
                  addItem(vL);
              }
          }
      }
      Any idea, why this happens?

      Kind Regards

      Comment


        #4
        Unfortunately, there's a conflict in your approach in that your CellClickHandler runs before the built-in Framework rowClick handler, so that the built-in handler receives a stale row value after your handler collapses the open group node. We're discussing internally whether this is something we should address, but for now you should be able to solve your issue using a SmartGwtTimer thusly:

        Code:
        @Override
        public void onCellClick(CellClickEvent event) {
            // TODO Auto-generated method stub
            if (lg.isGroupNode(event.getRecord())) {
                final GroupNode node = new GroupNode(event.getRecord());
        
                if (currentGroupNodeOpen == null) {
                    currentGroupNodeOpen = node;
                } else if (!currentGroupNodeOpen.equals(node)) {
                    SmartGwtTimer timer = new SmartGwtTimer() {
                        @Override
                        public void run() {
                            lg.closeGroup(currentGroupNodeOpen);
                            currentGroupNodeOpen = node;
                        }
                    };
                    timer.schedule(0);
                } else {
                    currentGroupNodeOpen = null;
                }
        
            }
        }
        Notes:
        • The timer will run immediately after the native rowClick() action's thread completes, so for a brief moment two nodes will be open, but it won't be visible as the redraw happens on a delay.
        • We've simplified some of the logic in your handler that didn't seem necessary, such as closing all nodes when the state machine indicates nothing is open.

        Comment


          #5
          Hi Isomorphic,

          perhaps you can make a setting like SectionStack.setVisibilityMode(). With this, a CellClickHandler would not be needed.

          Best regards
          Blama

          Comment


            #6
            Hi Isomorphic,

            1. that workaround works fine for me! Anyway, are you still discussing, if you address this issue, for a real fix?

            2.I stick with a modified version of the code in my first post, because we use a recordClickHandler, that directs to a dynamic form on each entry in the ListGrid. Before returning to the ListGrid we run invalidate cache and that gives every node a new ID, which makes the saved node then useless. That's not an issue for us, because it works fine. Just wanted to let you know, that in our case, the invalidate cache ruins the approach of saving the current group node.

            Kind Regards

            Comment


              #7
              Originally posted by Developer12145 View Post
              Hi Isomorphic,

              1. that workaround works fine for me! Anyway, are you still discussing, if you address this issue, for a real fix?
              We don't consider the provided solution a hack. Often it's necessary to run an action in a separate thread (i.e. outside the current execution stack) to avoid collision with default UI behavior, as in this case.

              However, we are discussing whether we might be able to make some internal changes to avoid this, but it isn't a high priority task.

              Originally posted by Developer12145 View Post
              2.I stick with a modified version of the code in my first post, because we use a recordClickHandler, that directs to a dynamic form on each entry in the ListGrid. Before returning to the ListGrid we run invalidate cache and that gives every node a new ID, which makes the saved node then useless. That's not an issue for us, because it works fine. Just wanted to let you know, that in our case, the invalidate cache ruins the approach of saving the current group node.
              Instead of saving the node itself, you could save the group value (a String in this case) that the node represents, and use it for comparison purposes where needed.

              Comment

              Working...
              X