PDA

View Full Version : Tree events seem out of order.



AspWhiz
29 Nov 2007, 6:11 AM
When I drag and item over a node in my tree, I noticed that the node expands automatically. Problem is, is that when this occurs, the beforenodedrop event fires and then the expandnode. I need to use the beforenodedrop to ensure that the user is not dropping an item that already exists under the node. Having the node expand after the beforenodedrop event doesn't allow me to compare the item being dragged with any of the children under the target node.

Does anyone have a suggestion or a work around for this?

FYI, I have tried to do things in nodedragover and cannot use nodedrop because at that point the item has already been dropped.

Thanks

AspWhiz
29 Nov 2007, 8:09 AM
Did I stump everyone once again?

new2ext
29 Nov 2007, 10:19 AM
Are you trying to restrict what nodes are allowed to be dropped? If I'm reading right, you don't want to allow a drop if the node is already in the drop tree. If so, you could look into modifying the onNodeOver function of the TreeDropZone

AspWhiz
29 Nov 2007, 11:04 AM
Yes basically I want to stop someone from dropping an item on the node if that item is already a child. Problem is, you cannot compare or do a search for any child node unless the node is expanded. The node has to be expanded because I'm doing a lazy load and populating the node with children when expanded.

The one solution that I have is to have the ajax call in my beforenodedrop event do a db check and call an error function on the client side, but I'd rather just be able to compare the dropped item to the child nodes. Unfortunately, the node expand event doesn't fire first which you'd think it would/should.

new2ext
29 Nov 2007, 1:29 PM
If you set expandDelay to 0 in dropConfig, it will stop the delay for the expand function. I can't perform any tests right now, but see if it helps.

AspWhiz
29 Nov 2007, 5:56 PM
Thanks but I'm not quite sure how to set that in the code. I tried a couple things but it kept not allowing my drop then. Could you provide and example of how you set that value. Thanks

new2ext
29 Nov 2007, 10:39 PM
var tree = new Ext.tree.TreePanel({
//Within TreePanel Config Parameters, put:
dropConfig: {expandDelay: 0 }
})

new2ext
29 Nov 2007, 10:53 PM
I just did a couple of tests, and depending on how fast the user drops the node, the beforenodedrop will still fire before expandnode. You should try setting your validation code in the onNodeOver event.


var tree = new Ext.tree.TreePanel({
//Within TreePanel Config Parameters, put:
dropConfig: {
onNodeOver: function(source, e, data){
//Your code here
}
}
})

Take a look at the other events in TreeDropZone for other possible solutions.
http://extjs.com/deploy/ext/docs/output/TreeDropZone.jss.html

AspWhiz
30 Nov 2007, 5:35 AM
The line you gave me doesn't allow me to drop. That is what I did try before. I think the problem is that when the node is expanded it does this:



loader: new Tree.TreeLoader({
dataUrl:'get-nodes.php'
}),


I think the problem of the events going "out of order" is cause the dropping of the node happens before the expand node get its response back when loading the nodes.

radio1
30 Nov 2007, 7:28 AM
Hey AspWhiz,

I have implemented what you're essentially trying to do as follows -- it may not be a perfect fit for your app.

Part of my app is essentially a file-explorer with 2 panes much like Windows Explorer, with a Folder tree on the left, and a grid displaying the files (but not subfolders) for the currently selected folder on the right. Like you, I'm "doing a lazy load and populating the node with children when expanded" via the Ext.tree.AsyncTreeNode. The drag/drop I support that sounds similar to your situation is the dragging of one or more files from the file grid to a different folder node in the tree -- which the user does to trigger the "move files" functionality.

Since these file actions must be performed on the server side anyway, I mostly don't restrict which nodes files can be dropped on on the client side, except for the sanity check of ensuring the files aren't dropped on the folder node they're already in. This is the sole check I make in my 'nodedragover' event handler.

I handle the other drops in my "beforenodedrop" event handler, where I:

- ALWAYS execute "dropEvent.cancel = true;" (I don't need the 'nodedrop' handler being called for this case)
- post a command to my server requesting the file(s) move
- if the server response indicates full success (all files could be moved), then simply delete those rows from the file grid
- if the server indicates any errors, I display the server-generated error message (which indicates which files were unable to be moved) in a modal popup window, then I lazily force a reload of the grid for the current folder node in the tree.

Since my tree ONLY contains folders (not files), I cannot do the client-side drop prevention you're attempting. However, even if my tree DID contain file nodes, I couldn't rely on client-side drop-prevention since server-side problems could still occur (due to multi-user and locked-file and changed-file reasons, etc.).
I'm guessing you're in a similar position in that content dropped on nodes in your tree must be validated and reflected server-side anyway, so why not simply drop the client side checking you're attempting. Or maybe you could do it as a minor optimization ONLY when the target node's children are already loaded.

Even if you do manage to achieve what you initially described, I don't see how you wouldn't confuse your end-user when they release the mouse button after dragging an item(s) over a tree node, and the app code hasn't yet figured out whether that drop is allowed.

Just my two cents -- I hope they're useful to you or someone.
Any comments/questions/thoughts/ideas/??? are always very welcome!

-radio1

AspWhiz
30 Nov 2007, 6:42 PM
radio1 -

Thanks for a very good response. Our situations are very similar and you have definitely given me a few ideas. I'll let you know how it goes.

As far as receiving the server error and displaying it in a modal window, could give a brief example. I've be using Ext.Ajax for the calls and PHP on the server side.

Thanks

AspWhiz
2 Dec 2007, 7:52 AM
The plot thickens....

If someone can explain to me why this happens, I would greatly appreciate it.

Since I'm doing a lazy load on my tree items, I noticed that if I drag over and drop immediately on an unexpanded node, it does work and my new leaf node gets placed as well as the appropriate leaf nodes loading.

If I pause for a few seconds when dragging over the node and wait until the node expands itself, I LOSE the source node. It doesn't drop at all and the drag data stays on the mouse and I get a firebug error that one of the attributes I am trying to reference that is part of the node being dropped is not there.

Any ideas? Can I stop the drop after a certain time has passed? Can I reload the source somehow? UGH!

All this is related in order for me to check if the user is trying to drop something that is already there.

radio1
3 Dec 2007, 6:10 AM
radio1 -

Thanks for a very good response. Our situations are very similar and you have definitely given me a few ideas. I'll let you know how it goes.

As far as receiving the server error and displaying it in a modal window, could give a brief example. I've be using Ext.Ajax for the calls and PHP on the server side.

Thanks

Hey AspWhiz,

Here's a snippet of code I'm using to post a command to the server and handle the response. Hopefully this is useful to you:

function onBeforeNodeDrop(dropEvent)
{
... fromNodeId -- identifier of the "current" node in my folder tree
... toNodeId -- (target.attributes.xId)
... fileList -- an array of filenames retrieved from the Grid's selection model

var target = dropEvent.target;
Ext.Ajax.request({
url:"MyJavaServletURL",
params: { cmd:'moveFiles', node:fromNodeId, toNode:toNodeId, files:fileList },
method:'post',
callback:function(opt,succ,resp){
var data = Ext.decode(resp.responseText);
if (data && data.rc=='0') {
for (i=0; i<gridRows.length; i++) {
var row = gridRows[i];
row.store.remove(row);
}
}
else
{
msg = (data? data.msg : "Some files could not be moved." );
msg = "<div style='text-align: center;'>" + msg + "</div>";
Ext.MessageBox.show({
title: 'Problem Moving Files...',
msg: msg,
buttons: Ext.MessageBox.OK
,minWidth:350
});
dropEvent.source.dragData.grid.store.reload();
}
}
});

...
...
}


Note that I'm FAR from a guru at this ExtJS stuff, and there may be some less-than-great code in there. But the above is working for me (with ExtJS 2.0rc1).

-radio1

radio1
3 Dec 2007, 6:38 AM
The plot thickens....

If someone can explain to me why this happens, I would greatly appreciate it.

Since I'm doing a lazy load on my tree items, I noticed that if I drag over and drop immediately on an unexpanded node, it does work and my new leaf node gets placed as well as the appropriate leaf nodes loading.

If I pause for a few seconds when dragging over the node and wait until the node expands itself, I LOSE the source node. It doesn't drop at all and the drag data stays on the mouse and I get a firebug error that one of the attributes I am trying to reference that is part of the node being dropped is not there.

Any ideas? Can I stop the drop after a certain time has passed? Can I reload the source somehow? UGH!

All this is related in order for me to check if the user is trying to drop something that is already there.

When dragging GridPanel rows to a TreePanel node, I didn't ever receive a ".dropNode" value in my dropEvent -- which I assume was because the dragged/dropped data WASN'T a node (it was one or more rows).

Anyway, I use this null value as my indicator that the dropped data must be from the Grid (and not another Tree node). I then retrieve the rows dropped from the Grid's selection model. There may be a much better way to do this, but this snippet is working for me:



function onBeforeNodeDrop(dropEvent)
{
if (dropEvent.dropNode == null) // must be a drag from the file grid
{
// do all processing HERE and cancel the event -- don't try to pass through to onNodeDrop
dropEvent.cancel = true;

var grid = MyFileGrid; // reference to my File Grid
var gridRows = grid.selModel.selections.items;

var fileList = [];
for (i=0; i<gridRows.length; i++) {
fileList.push(gridRows[i].data.filename); // .filename is one of my data fields in the grid
}
fileList.sort();

...
...


I hope this helps you get around your problem.

-radio1

AspWhiz
3 Dec 2007, 8:37 AM
radio1

Again, thank you! With now checking some items as null and wrapping code in try/catch I am able to at least show a msg box with poss errors to the user and my tree stays intact.

I have a couple of specific questions that maybe you can answer:

1. In the beforenodedrop, what is the difference doing a dropEvent.cancel = true or a return false? They both seem to work and do the same thing. Any benefit of either?

2. I'm using Ext.Ajax to make the calls. When calling a failure method, what is the reponse you have to send back from the server? I'm using PHP, but is it an HTTP response or throwing a PHP error? I'm just not sure about this one.

Thanks again!!

radio1
3 Dec 2007, 9:31 AM
1. In the beforenodedrop, what is the difference doing a dropEvent.cancel = true or a return false? They both seem to work and do the same thing. Any benefit of either?


I'm not sure -- I now see that I'm actually doing BOTH of those things in that particular method. Check out the ExtJS source for more info I guess.



2. I'm using Ext.Ajax to make the calls. When calling a failure method, what is the reponse you have to send back from the server? I'm using PHP, but is it an HTTP response or throwing a PHP error? I'm just not sure about this one.


I'm not sure what you mean by "calling a failure method", and not being a PHP guy I'm not clear on what "throwing a PHP error" is/does.
If you're asking what response does my server-side app (a Java servlet, by the way) return when my "move files" operation fails for some reason, here's a sample of good and bad responses.

Move successful:


{rc:'0'}

Move error:


{rc:'1',msg:'Error: Unable to move the following files:<BR /><BR />somefile.doc'}

You can see my JavaScript response handling in my previous post.



Thanks again!!

You're welcome. Good ongoing luck with your project.
-radio1