Duplicate nodes when moving in dynamically loading tree

Re: dhtmlxTree Pro 3.0 build 110707

Hi,

I’m having a problem with moveItem() on a tree that fetches XML dynamically via a PHP script.

When moving a node to a new parent (item_child mode), my PHP scripts perform the database changes to move the node first, and if successful, I call moveItem().

Unfortunately, in certain cases, this leads to a duplicate copy of the subject node. This occurs when the new parent hasn’t been opened before (it’s children aren’t loaded). What happens is the move occurs first, then the new parent is expanded (fetches fresh XML which already includes the moved node) so you end up with two copies.

I’ve tried a few workarounds but nothing proved fruitful:

  • if new parent closed, open it before moveItem().
  • if new parent closed, delete subject node, then just refresh target parent.
  • if new parent closed, moveItem() then cycle children of target parent and delete whichever node has the same text label as the subject node but different id.

Other than calling moveItem() first THEN moving in database, does anyone have any suggestions?

Thanks,
E71

Hi,

are nodes moved from another Tree ? If the nodes are moved within the same, such a problem should not occur as unique ids in Tree is a requirement. So, server-side script should return items with unique ids.

If you call moveItem to move an item from another tree, you may change its id:

var newItemId = itemId+"_"+(new Date()).valueOf()
tree.changeItemId(itemId,newItemId);
tree.moveItem(newItemId,…);

Hi,

Thanks for the response.

I believe what’s it’s doing is, after moveItem() moves the node to the unopened target parent, it fetches XML that includes that node we just moved, so it automatically alters the ID of one of those (not sure which one) to make it unique. Basically it appends a timestamp to the ID.

E.g. When you move node “Apple” (ID: ‘123’) to unopened target parent “Fruits” (ID: ‘456’), you end up with two “Apple” nodes under “Fruits”, one with ID ‘123’, the other with ID ‘123_1328730343946’.

Sorry, I just noticed you already mentioned the timestamp part under moving from another tree which I embarrassingly didn’t fully read because I assumed it’s not relevant as I’m moving from the same tree.

I’m starting to think it may be a duplication of the tree object somewhere in my code. Will update this thread when I find out.

Thanks,
E71

Unfortunately, that doesn’t appear to be the case, I tested moveItem() on cut-down version of my code, which is just:

tree = new dhtmlXTreeObject('category_tree', '', '', 0);
tree.setImagePath('../../lib/dhtmlxTree-3.0/codebase/imgs/csh_dhx_skyblue/');
tree.enableSmartXMLParsing(true);
tree.enableDistributedParsing(true);
tree.setXMLAutoLoading('xml.php');
tree.loadXML('xml.php?id=1&root_id=1&open=1');
tree.attachEvent('onClick', function(nodeId) {
  $('#node_id').val(nodeId);
}

Can we reproduce the problem in the dhtmlxTree/samples/12_loading_processing_data/13_tree_dyn_loading.html sample if you enable drag-n-drop in tree? We have not managed to reproduce the problem.

I couldn’t think of an easy way to test it so I wrote a few files, they should help demonstrate the issue:
moveitem_bug.zip (2.13 KB)

Testing is a bit awkward, because you need to make a small modification to xml.php file in the middle of the test.

Instructions:

  • Load index.html
  • Modify xml.php by un-commenting the first line (this basically simulates the node move)
  • Click node ‘New York’
  • Click the ‘Move selected node…’ button

This test will result in two ‘New York’ nodes under ‘Places’ – unless you open ‘Places’ first before you simulate the movement of the ‘New York’ node.

You can also test with drag n drop but obviously shouldn’t hold the cursor over the target node for too long!

tree_after.php returns “New York” item. And there is one more “New York” that you are moving in tree. So, Tree works correctly.

Hi.

I’m not sure how this is considered working tree behavior.

My requirements are as follows:

  • User attempts to move a node in dhxTree, return false for onDrag event handler and call server-side scripts inside an iframe.
  • Server-side scripts move the node within the database.
  • If server-side database queries were successful, then call the parent window’s dhxTree.moveItem() function.

I’m very surprised that your other customers haven’t already reported this bug or complained about its inability to handle this scenario, since I’m sure a lot of people use dhxTree as a front-end representation of their dynamically changing back-end tree data.

Although a moveItem() before server-side changes will “fix” this, there’s obviously an importance to ensuring the changes have been made permanent (in the database) before the tree shows it so.

How would you suggest I go about doing this?

Hi,

it is not a bug. It is the issue your implementation.

In the onDrag handler you may check the child nodes of an item where dragged item is going to be dropped in. You can use hasChildren method which can return:

  • true - for node with dynamic children that are not loaded yet
  • number of items

For the items that hasChildren returns true, moveItem should not be used - they will be loaded with other child nodes.