Announcement

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

    TreeGrid drop handling problem/Tree.move() method does not work

    Hi!

    I have a databound treeGrid (parent type) where it is possible to drag and drop nodes (in the same folder or into different folders). Before the drop become effective, I need to do some server-side checks. I want the move to be done only if the check is OK. So I implemented a dropHandler but it does not work. Tree.move(TreeNode, TreeNode, Integer) method seem to work only in different folders and to ignore the move index...
    Can anyone give me some help?

    Code:
    final ResultTree tree = new ResultTree();
    tree.setModelType(TreeModelType.PARENT);
    [...]
    this.treeGrid.setDataProperties(tree);
    this.treeGrid.setDataSource(dataSource);
    this.treeGrid.setAutoFetchData(true);
    this.treeGrid.setSaveLocally(false);
    this.treeGrid.setCanReorderRecords(true);
    this.treeGrid.setDragDataAction(DragDataAction.MOVE);
    this.treeGrid.setCanAcceptDroppedRecords(true);
    [...]
    this.treeGrid.addFolderDropHandler(new FolderDropHandler() {
                @Override
                public void onFolderDrop(final FolderDropEvent event) {
                    if (event.getNodes() != null && event.getNodes().length > 0) {
                        final TreeNode movedNode = event.getNodes()[0];
                        final String sourceParentId = movedNode.getAttribute("parentId");
                        final Record targetParentNode = event.getFolder();
                        final String targetParentId = targetParentNode.getAttribute("id");
                        final Integer moveIndex = event.getIndex();
                        RestRequest.doGet(myPath,
                                        myResource + movedNode.getAttribute("id") + "/in/" + targetParentId + "/at/"
                                                + moveIndex,
                                        new RequestCallback() {
                                            @Override
                                            public void onError(final Request request, final Throwable exception) {
                                                SC.warn("Error while performing request to move an item in tree.");
                                            }
    
                                            @Override
                                            public void onResponseReceived(final Request request, final Response response) {
                                                if (response.getStatusCode() != Response.SC_OK) {
                                                    final String httpResponseText = response.getText();
                                                    final JSONValue body = JSONParser.parseStrict(httpResponseText);
                                                    final JSONObject resp = body.isObject().get("response").isObject();
                                                    final String errorMessage = resp.get("errors").isString().stringValue();
                                                    SC.warn(errorMessage);
                                                } else {
                                                   this.treeGrid.getTree().move(movedNode, (TreeNode) targetParentNode, moveIndex);
                                                }
                                            }
                        });
    
                        event.cancel();
                    }
                }
    });

    My env :
    SmartGWT 5.1p-20171219
    GWT 2.7
    Firefox 38.2.1 ESR

    #2
    Why are you doing this via some kind of RestRequest API? If you simply implement the "update" operation on the DataSource you provide to the TreeGrid, the TreeGrid will use the DataSource to move the node, and it is fine for your server to report errors in the usual way. If you are, in addition, trying to save the actual position of the move, take a look at the Persistent Reorderable Tree sample, which does this.

    Trying to directly manipulate the Tree with a move() call doesn't make sense here. Since you've got a DataSource, the Tree is just a temporary client-side cache of records, and if you bypass the normal save mechanism, the right way to have the cache updated is to use DataSource.updateCaches(). Again, see the Persistence Reorderable Tree sample for details.

    Comment


      #3
      OK. Thanks for the quick reply.
      I do not remember why we choose to use the RestRequest API instead of the update... I will take a look this way.
      I will also take a look at the Persistent Reorderable Tree sample code. But for the moment, I do not know why but the EE samples do not display any data to me.

      Comment


        #4
        We're not currently seeing an issue with EE samples not displaying data. It's possible you had unlucky timing and tried to use EE Showcase samples you had already loaded in your browser during the nightly server restart (which installs the latest build of the framework). Let us know if the problem persists for you.

        Comment


          #5
          I've cleared my browser cache, I tried with another browser... I 'm still able to see EE samples HMI and code but everywhere "No item to show" is displayed. Whereas basic samples are OK.

          Comment


            #6
            I took a look at the Persistent Reorderable Tree sample and try to apply it to my case. My folderDropHandler is now :
            Code:
              
             this.treeGrid.addFolderDropHandler(new FolderDropHandler() {            
            @Override
                         public void onFolderDrop(final FolderDropEvent event) {
                            if (event.getNodes() != null && event.getNodes().length > 0) {
                                final TreeNode movedNode = event.getNodes()[0];
                                final String sourceParentId = movedNode.getAttribute("parentId");
                                final Record targetParentNode = event.getFolder();
                                final String targetParentId = targetParentNode.getAttribute("id");
                                final Integer moveIndex = event.getIndex();
                                RPCManager.startQueue();
                                DSRequest request = new DSRequest(DSOperationType.UPDATE, treeGrid.getUpdateOperation());  
                                movedNode.setAttribute("sortNumber", moveIndex);
                                movedNode.setAttribute("parentId", targetParentId);  
                                treeGrid.updateData(movedNode, null, request);
                                RPCManager.sendQueue();
                           }
                         }
            });
            I get the server side call well but I think I miss something : even if my server fails its update (and answers with an error status), the node is even moved in the tree (as I removed the event.cancel()).

            Then behaviour I would like is :
            - the user drags and drops the node from a folder to another (maybe the same) at a given index
            - the server is called to do some checks
            - if the server replies ok -> the move is done in the tree
            - otherwise (if the server responds ko) -> the move is cancelled and the node keeps its original place.

            How can I do this?
            Last edited by MelieZxy; 11 Jan 2017, 06:04.

            Comment


              #7
              I have not found any way to implement the previously described behaviour yet... I hope you may give me some help.
              But I have another problem that can be related (it deals with event managing).
              My customer would like to put a confirmation popup when droping a node (if confirm, the node is dropped, otherwise, the node keeps its previous place). But if I put this :
              Code:
              this.treeGrid.addFolderDropHandler(new FolderDropHandler() {            
              @Override
                           public void onFolderDrop(final FolderDropEvent event) {
                              SC.confirm("My message", new BooleanCallback() {
                                      @Override
                                      public void execute(Boolean value) {
                                          if (value != null && value) {
                                              if (event.getNodes() != null && event.getNodes().length > 0) {
                                                final TreeNode movedNode = event.getNodes()[0];
                                                final String sourceParentId = movedNode.getAttribute("parentId");
                                                final Record targetParentNode = event.getFolder();
                                                final String targetParentId = targetParentNode.getAttribute("id");
                                                final Integer moveIndex = event.getIndex();
                                                RPCManager.startQueue();
                                                DSRequest request = new DSRequest(DSOperationType.UPDATE, treeGrid.getUpdateOperation());  
                                                movedNode.setAttribute("sortNumber", moveIndex);
                                                movedNode.setAttribute("parentId", targetParentId);  
                                                treeGrid.updateData(movedNode, null, request);
                                                RPCManager.sendQueue();
                                              }
                                          } else {
                                               [...]
                                          }
                                      }
                                  });
                           }
              });
              when the user confirms, the server call is well done, but the move in the tree is not done. As if the event has been forgotten.

              Why?
              Is it possible to implement the behaviour my customer wants?
              How?

              Comment


                #8
                Both problems are related. In your previous attempt, you are directly modifying the "movedNode" before the server call; that's why it's always changing regardless of what the server does. You need to instead just make a copy of the data in the node, and use that with your server call (see for example DataSource.copyRecord()).

                As previously mentioned, once the server call completes successfully, you use DataSource.updateCaches() to tell the Tree to update.

                Structuring your code this way also avoids needing access to the event object when the event has already completed.

                Comment


                  #9
                  Oh! Thanks for your last reply. All of it becomes clearer for me!

                  Here is my new function :
                  Code:
                  this.treeGrid.addFolderDropHandler(new FolderDropHandler() {
                              @Override
                              public void onFolderDrop(final FolderDropEvent event) {
                                      final TreeNode movedNode = event.getNodes()[0];
                                      final String sourceParentId = movedNode.getAttribute("parentId");
                                      final Record targetParentNode = event.getFolder();
                                      final String targetParentId = targetParentNode.getAttribute("id");
                                      final Integer moveIndex = event.getIndex();
                                      
                                      RPCManager.startQueue();
                                      DSRequest request = new DSRequest(DSOperationType.UPDATE, treeGrid.getUpdateOperation());
                                      Record copyNode = dataSource.copyRecord(movedNode);
                                      copyNode.setAttribute("sortNumber", moveIndex);
                                      copyNode.setAttribute("parentId", targetParentId);
                                      DSCallback updateCallback = new DSCallback() {
                                          @Override
                                          public void execute(DSResponse dsResponse, Object data, DSRequest dsRequest) {
                                              dataSource.updateCaches(dsResponse, dsRequest);
                                          }
                                      };
                                      treeGrid.updateData(copyNode, updateCallback, request);
                                      RPCManager.sendQueue();
                                      event.cancel();
                                  }
                              }
                          });
                  (my DSResponse contains all the brother nodes of the movedNode (in source folder and target folder))

                  It works better than before but a problem remains : the tree display is not refreshed by updatesCaches() call. The movedNode become displayed at the right place only after I expand another folder (loaded by demand).
                  How can I correct this problem? Did I do something wrong? I did not found any consistent updateCaches() sample anywhere :(

                  (I ran my tests on a SmartGWT5.0p-20151120 because I need to implement this function on an old version of my app)
                  Last edited by MelieZxy; 13 Jan 2017, 07:15.

                  Comment


                    #10
                    Because you are now using DataSource.updateData(), you should not even need the updateCaches() call, since cache updates are automatic when the TreeGrid is bound to the DataSource and DataSource operations are used.

                    We can't tell what's wrong here from this partial code. Possible problems:

                    1. The TreeGrid is no longer bound to the DataSource

                    2. You've provided your own Tree or ResultTree via setData(), so the automatic connection to the DataSource isn't set up (as it would be if you call TreeGrid.fetchData())

                    3. The data returned from the server in response to updateData is wrong in some way - primary key values don't match what's already loaded in the tree, data is partial, something like that

                    Comment


                      #11
                      Hello!

                      Sorry for the delay, I had other problems to fix.

                      Thanks for your last reply.

                      I've check my code and app and I think my datasource remains well set because the load on demand functionnality still works correctly.

                      But maybe I have some problem on the data returned in my updateData response. I wonder what should it return exactly?
                      For instance if I have the following sample tree :
                      Root R
                      + Folder 1
                      - Folder 2
                      ° Leaf 21
                      - Folder 3
                      ° Leaf 31

                      If I move leaf 21 from Folder 2 to Folder 3, what should contain the updateData response? Full tree? Folder 2 and Folder 3 contents? only Leaf 21?

                      I precise : my data is sorted on an attribute "sortNumber" on each item.
                      Last edited by MelieZxy; 14 Feb 2017, 06:29.

                      Comment


                        #12
                        It works!!!!!!! \o/ \o/ \o/ \o/ \o/ \o/

                        I returned all the modified items (all folder 2 content and all folder 3 content because all their "sortNumber" changed). But the case I was testing was not exactly the one described above. My item was dropped in the same folder as it comes, only the place changed. And that was the unique case that does not work!
                        So I tried to add a treeGrid.sort("sortNumber") in my updaeData callback and it works! \o/
                        I don't know why this is needed, nor why a treeGrid.sort() does not work whereas my treeGrid is initialized whith this.treeGrid.setSortField("sortNumber"); ?

                        Is it a known bug in my version (I tested on 5.0p 2015-11-20 nightly build)? Has it been fixed on 5.1 version?

                        Very great thanks for your help to improve my understanding and my code!

                        Comment


                          #13
                          Hi MelieZxy.

                          did you look at the sample in the server showcase? You could see the data sent/returned for a Drag-n-Drop action there.

                          Isomorphic: In the sample, moving an item one position up or down within the same folder issues not 2 (queued) requests, but one for every sibling, also if the data does not change for most of them.

                          Best regards
                          Blama

                          Comment


                            #14
                            We don't see a problem with needing a manual sort call in the latest, so this may be a long-fixed bug, or some other issue in your approach. You should update to the latest patched version regardless, as well as to 5.1.

                            @Blama: the sample code in the Showcase updates all nodes because on a given drop, every node in the folder which is forward of the drop position has its index changed. A application could instead use sparse indexes to avoid this, but it's not really a large cost unless folders are very large.

                            Comment

                            Working...
                            X