PDA

View Full Version : Ext.ux.tree.RemoteTreePanel



jsakalos
12 Dec 2008, 4:13 AM
I'm right now developing a taxonomy system and I was in need of a tree that would be stored at server with UI at client - I think quite common requirement, right? I've done it already before for various trees, e.g. my FileTreePanel.

I've been too lazy to write the same code again and again so I put all basic operations into extension: Ext.ux.tree.RemoteTreePanel. The extension doesn't change appearance or behavior of the standard Ext.tree.TreePanel too much but it implements the following logic:

1. User makes a change of the tree (create node, rename node, delete node, D&D node)
2. Request is sent to server to execute, save this change.
3.a) Update GUI on success
3.b) Revert GUI to previous state on failure + display error message delivered from server.

If you're interested see live demo at http://remotetree.extjs.eu

All your comments, bug reports or ideas for improvements are welcome.

Note: I cannot publish the backend of the example so it makes no sense to ask me for it. Of course, you are free to analyze what is sent to the server and what comes back and to implement your own server solution.

galdaka
14 Dec 2008, 2:15 AM
Hi Jsakalos,

http://remotetree.extjs.eu (http://remotetree.extjs.eu/) not work! ;)

Greetings,

Frenky
14 Dec 2008, 3:37 AM
great extend
thanks very much!
this is just I needed

jsakalos
14 Dec 2008, 9:57 AM
It must had been some temporary problem - does it work now?

Hi Jsakalos,

http://remotetree.extjs.eu (http://remotetree.extjs.eu/) not work! ;)

Greetings,

galdaka
14 Dec 2008, 11:48 AM
It must had been some temporary problem - does it work now?

Oh yes. Thanks!!

;)

hpet
15 Jan 2009, 8:19 AM
@jsakalos

Nice example.

Can you tell how does your example handle multi-user environment. For example if multiple people have tree loaded, then one makes a change on an already altered tree structure by someone else?

Also, if you can share, how did you manage hierarchical data in the background... and why did you choose this aproach. Standard "adjucency model" or a bit more advanced nested set model?

Thanks again!

jsakalos
15 Jan 2009, 8:55 AM
There is no special logic for MU environment implemented at client side.

I don't know what's "adjucency model". I use principle similar to this: http://www.sitepoint.com/article/hierarchical-data-database/2/ enhanced by myself.

hpet
15 Jan 2009, 9:29 AM
Thanks for reply.
Yes, preordered tree (nested as I mentioned) is also my choice.
By adjucency model I simply ment parent/ child relationship maintained through parent_id only.

I am thinking about this MU issue, but then I wonder if this is realy something I should spend much time on... this may rarely happen and I guess simple error message and refresh would do. Would you agree?

jsakalos
15 Jan 2009, 9:36 AM
I don't care too much about MU. For example, if user tries to move a branch to a node that has been deleted by another user he/she gets error message. Then he can reload the tree.

rusty124
15 Jan 2009, 10:36 AM
Nifty...
Firefox works great. In IE7 menu images are offset into the menu text.

jsakalos
15 Jan 2009, 11:19 AM
It can be a problem particular to my page... A conflicting css... Do you have an idea?

alex-t.de
15 Jan 2009, 2:38 PM
I don't care too much about MU. For example, if user tries to move a branch to a node that has been deleted by another user he/she gets error message. Then he can reload the tree.

Hi!

I'm also working on a LiveTree, as I'd call it. When I was planing the application wich use this tree, I realised pretty early that you have to look after using by multiple users. I think every kind of application should do so, when more than one user at a time is able to access the UI which allows to change common data.

Imagine you don't care about this problem, one worst case could be: You spend a lot of time by editing the content of an item from the tree. When you try to save your changes, an error message appears "Sorry, but the item you were editing no longer exists." Another user deleted your item just a minute before.

Another problem could be when you and another user are doing a lot of small changes (like renaming of items) at the same time. Then you could get a lot of error messages, and that would be confusing or at least annoying.


Some of the tricky problems about LiveTrees are:

Check every x seconds for changes on server side. If there are some changes do an UI update.
When you are editing an item, then this (and the parents) should be blocked from deleting or moving by other users. This block should be done every z seconds, so the server can detect your disconnection from the network.


My LiveTree loads data on-demand from a RoR-backend. The update algo should look like this:

Every x seconds call the update controller on the server side and send the ids of items you already loaded in the tree. The controller should check for all kinds of updates and note the all parent_ids of the modified items. Some optimization is needed to prevent from double updates.
The UI controller on the client should say all the items with id equals parent_id that they have to update their children items.


At the moment I'm working on a prototype of this. I hope, that the user experience will be ok.

Let me say something about the motivation behind this solution. First of all it's quite hard to implement all kind of UI update operations like 'removing a subtree', 'updating item attributes', 'adding a subtree' and 'adding a sibling item'. I've decided to go the lazy way because of some reasons, for instance pressure of time. So I try to parent item and reassure the selected item is visible. One problem is the delay of the lazy loading tree and especially the animation, wich I hope to be able to disable.

Think about these ideas. Maybe it is not to difficult to implement something like this. But every error message that can be prevented is soft of a bug. Reduce messages like "This item doesn't exist any longer", user don't like them.

jsakalos
15 Jan 2009, 3:21 PM
Well, we host 1000+ clients (each has his own trees) so only bandwidth overhead connected with checking/locking is not worth the effort to handle the situation that can happen very, very rarely.

Of course, YMMV.

Post an example when you're done with it anyway.

alex-t.de
16 Jan 2009, 2:29 AM
Well, we host 1000+ clients (each has his own trees) ...

If the users don't share one tree with each other, but every one has its own, then there is no multi user problem.

In my avg cases there are 10+ users working on the tree structure at the same time. So I really need a more conflict-less situation.




Post an example when you're done with it anyway.

I'll do so, but that can take some weeks. I've make a ToDo for a post.

jsakalos
16 Jan 2009, 5:38 AM
Just to clarify: 1 client = one company = many users, sorry for not being percise.

crp_spaeth
9 Feb 2009, 1:28 AM
Hey Alex,

I would not extend the Tree it self since the Updating thing should be placed into the TreeLoader...

I wrote a small "SyncableTreeLoader" that i think does exactly what you need!
You can use it as you use the normal Treeloader. If you want to ask the tree for an update just call the requestData with a third parameter (update) true.

I think the Code is selfexplaining ...




Ext.ns('Ext', 'Ext.ux', 'Ext.ux.tree');

/**

* @class Ext.ux.tree.SyncableTreeLoader
* @extends Ext.tree.TreeLoader
*
*
* A SyncableTreeLoader provides the same functionality as its Baseclass (Ext.tree.Treeloader) plus the
* possibility of lazy updating an existing Structure of TreeNodes from a specified Url.
*
* The response must be a JavaScript Object definition whose Members are (by default) "deleted", "updated", "added"
*
* "deleted" contains a simple Javascript Array definition of the TreeNode-Id that should be deleted
*
* "updated" contains a JavasScript Array defintion contaioning the Object definition of the updated
* TreeNodes with its new attribute properties
*
* "added" contains a JavaScript Array of definition containing the Object definition of the treeNodes
* that should get Added to the Tree. Cause the Tree needs to know where to insert/append the TreeNode,
* the definition of the Node needs to contain an Attribute with the Id of its Parentnode "Parentnode"
* and Optional its Presilbing.
*
* A possible Response looks like this:

* <pre><code>
{
"deleted" : ['nodeId123'],
"updated" : [{
"leaf" : false,
"id" : "nodeId342",
"children" : [{
"leaf" : false,
"id" : "node12314",
"children" : [],
"attr" : {
"preSilbing_id" : null,
"parent_id" : "nodeId342",
"Dokumente" : "0",
"leaf" : false,
"text" : "childs text"
}
}
],
"attr" : {
"parent_id" : "parentNodeId",
"preSilbing_id" : null,
"text" : "Node Text",
"leaf" : false
}
}],
"added" : [{
"leaf" : false,
"id" : "nodeId555",
"children" : [{
"leaf" : false,
"id" : "node12314",
"children" : [],
"attr" : {
"preSilbing_id" : null,
"parent_id" : "nodeId342",
"Dokumente" : "0",
"leaf" : false,
"text" : "childs text"
}
}
],
"attr" : {
"parent_id" : "RootNodeID",
"preSilbing_id" : "FirstChildsId",
"text" : "Node Text",
"leaf" : false
}]
}
</code></pre>
* @author Martin Spaeth
* @copyright (c) 2008, by Martin Spaeth
*/
Ext.ux.tree.SyncableTreeLoader = Ext.extend( Ext.tree.TreeLoader, {

/**
* @cfg {string} updateParamName
* Parametername for the requesttype
*/
updateParamName: 'request',

/**
* @cfg {string} updateParamValue
* value of the Parameter to show the server that this is an updaterequest
*/
updateParamValue: 'update',

/**
* @cfg {String} updatedName
* Name of the array containing the nodes that should get updateted
*/
updatedName: 'updated',

/**
* @cfg {String} deletedName
* Name of the array containing the Id's of the nodes that should get deleted
*/
deletedName: 'deleted',

/**
* @cfg {String} addedName
* Name of the array containing the nodes that should get added
*/
addedName: 'added',

/**
* @cfg {String} parentIDAttr
* name of the attribute containing the parentId of a node
*/
parentIDAttr: 'parentIdAttr',
/**
* @cfg {String} preSilbAttr
* name of the attribute containing the preSilbingId of a node
*/
preSilbAttr: 'preSilbingIdAttr',

clearOnLoad : true,

/**
* @cfg tree {Ext.tree.Tree} the Tree this Treeloader is instantiated for
*/
tree: undefined,

/**
* Create a String containing all needed Request Parameters
* @param {Ext.tree.TreeNode} node
* @param {boolean} update
* @return {String} Parameterstring for a Request z.b. node=432&updete=true
*/
getParams: function(node, update){
var buf = [], bp = this.baseParams;
for(var key in bp){
if(typeof bp[key] != "function"){
buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
}
}
buf.push("node=", encodeURIComponent(node.id));
if(update){
// adding the updateparameter
buf.push("&"+this.updateParamName+"=", encodeURIComponent(this.updateParamValue));
}
return buf.join("");
},


/**
* RequestData Function with the possibility to fire an updaterequest
* @param {Ext.tree.TreeNode} node the Node for wicht the data should be requested
* @param {function} callback a callbackfunction
* @param {boolean} update is it an updaterequest
*/
requestData : function(node, callback, update){
if(this.fireEvent("beforeload", this, node, callback) !== false){
this.transId = Ext.Ajax.request({
update: update,
method:this.requestMethod,
url: this.dataUrl || this.url,
success: this.handleResponse,
failure: this.handleFailure,
scope: this,
argument: {callback: callback, node: node},
params: this.getParams(node, update)
});
}else{
// if the load is cancelled, make sure we notify
// the node that we are done
if(typeof callback == "function"){
callback();
}
}
},

/**
* the function that processes the Response an handles all the Update logic
* @param {Object} response from the Server
* @param {Ext.tree.TreeNode} node The Node the Response is for
* @param {function} callback
*/
processResponse : function(response, node, callback){

var json = response.responseText;
var update = response.options.update;
var tree = node.getOwnerTree();

try {
var o = eval("("+json+")");
// is the response part of an update request?
if(update){

// delete Nodes
var del = o[this.deletedName];
if(del && del.length){
for(var i = 0; del.length > i; i++){
var delNodeId = del[i];
tree.getNodeById(delNodeId).remove();
}
}

// Add all Nodes from the added Array Responsed by the server
var added = o[this.addedName];
if(added && added.length){
for(var i1 = 0; added.length > i1; i1++){
var addedNode = added[i1];

/**
* @type Ext.tree.TreeNode
*/
var parent = tree.getNodeById(addedNode.attr[this.parentIDAttr]);
var preSilbing = tree.getNodeById(addedNode.attr[this.preSilbAttr]);

parent.beginUpdate();
// Append the Node to the Parent or Insert it after the presilbing.
if(!preSilbing){
parent.appendChild(this.createNode(addedNode));
} else {
parent.insertBefore(this.createNode(addedNode), preSilbing.nextSibling);
}

parent.endUpdate();
}
}

// Update all the nodes the Update array contains
var updated = o[this.updatedName];
if(updated && updated.length){
for(var i2 = 0; updated.length > i2; i2++){
var updatedNode = updated[i2];

/**
* @type Ext.tree.TreeNode
*/
var toUpdate = tree.getNodeById(updatedNode.id);

toUpdate.beginUpdate();
// toUpdate.updateNode(updatedNode);

// update should only handle the attributes of a node nor the children
if(updateNode.children) {
delete updateNode.children;
}

Ext.apply(toUpdate, updateNode);


// update the text of the node
if(updateNode.text){
toUpdate.setText(updateNode.text);
}

// replace the Icon
if(updateNode.iconCls){
Ext.fly(toUpdate.getUI().getIconEl()).replaceClass(oldIconCls, updateNode.iconCls);
toUpdate.iconCls = updateNode.iconCls;
}

// replace the quicktip
if(updateNode.qtip) {
var ui = toUpdate.getUI();
if(ui.textNode.setAttributeNS){
ui.textNode.setAttributeNS("ext", "qtip", updateNode.qtip);
if(updateNode.qtipTitle){
ui.textNode.setAttributeNS("ext", "qtitle", updateNode.qtipTitle);
}
}else{
ui.textNode.setAttribute("ext:qtip", updateNode.qtip);
if(updateNode.qtipTitle){
ui.textNode.setAttribute("ext:qtitle", updateNode.qtipTitle);
}
}
}

toUpdate.endUpdate();
}
}

if(typeof callback == "function"){
callback(this, node);
}
}
else {
node.beginUpdate();
for(var i = 0, len = o.length; i < len; i++){
var n = this.createNode(o[i]);
if(n){
node.appendChild(n);
}
}
node.endUpdate();
if(typeof callback == "function"){
callback(this, node);
}
}

}catch(e){
this.handleFailure(response);
}
}
});

crp_spaeth
9 Feb 2009, 4:53 AM
I just pasted my extension into a new Thread

http://extjs.com/forum/showthread.php?p=285378#post285378

Simon1101
11 Feb 2009, 9:09 AM
Hi jsakalos,

i'd like to have a look at the php-classes required by process-request.php. Is that possible?

btw, very nice remote-tree ;-)

Simon

jsakalos
11 Feb 2009, 9:11 AM
Sorry, server side is proprietary.

Simon1101
11 Feb 2009, 9:19 AM
no problem, thanks anyway!

Minnow
11 Feb 2009, 9:35 AM
Hey - cool toy.

You need to insert the following at line 476

case 'insertChild':

so that it reads:


if(true !== o.success) {
this.showError(o.error || o.errors);
switch(options.action) {
case 'appendChild':
case 'insertChild':
options.node.parentNode.removeChild(options.node);
break;
default:
break;
}
return;
}

jsakalos
11 Feb 2009, 9:41 AM
Node stays on error?

jsakalos
11 Feb 2009, 9:42 AM
Oh, yes, now I remember. I've added insertChild later and forgotten to put it here. Thank you for pointing out.

cybersys
25 Feb 2009, 1:57 AM
I thiknk that a node.select when show context menu is a good approach because when i select a node and then right click to another for insert a new node the selected node stays until i insert the new node.

It might be confusing for some people

just a suggestion

Thanks is really great job

jsakalos
25 Feb 2009, 2:35 AM
Node name you're working with is always displayed in bold as first non-editable item of context menu. However, users sometimes "do not see" so I've implemented your suggestion.

I've also released 1.0 stable version - there were no bugs reported so far, neither feature requests.

wayned@escc
3 Mar 2009, 3:58 AM
I've added some code to allow for editable: false

Please take a look and let me know if you think it's good enough to be included in your version.

w://

jsakalos
3 Mar 2009, 11:51 AM
Could you please describe the changes, what's purpose of them, etc.?

wayned@escc
4 Mar 2009, 2:21 AM
Could you please describe the changes, what's purpose of them, etc.?

Sure.

I just changed it so that when 'editable: false' it:

- doesn't error
- shows a limited set of items in the context menu (only those items that do not pertain to editing).

If you do a diff on the file on your site to the one I uploaded you'll see they are really only minor changes but it makes sense to have this working as the property (editable) exists but the functionality didn't.

I have also extended this plugin to make it easier for people working with castle monorail bringing the following to the table:

- ability to specify controller class
- ability to specify actions for each operation (rename, add, delete etc...)

This means that we can have a seperate controller action for each tree operation - cleaner, simpler, easier to understand.

If anyone's interested I can upload.

Cheers for a cool plugin :)

w://

jsakalos
4 Mar 2009, 11:54 AM
Oh, yes, editable:false is unfinished work of mine. I'll complete it soon. No idea what's "castle monorail" though.

wayned@escc
5 Mar 2009, 4:27 AM
Hey

The file I uploaded has the editable: false functionality implemented so you can use that if you like :)

Castle Monorail is a shiz hot MVC for .NET - The whole Castle stack is worth checking out if you're a .NET dev:

http://www.castleproject.org/

w://

jsakalos
5 Mar 2009, 9:08 AM
I've seen it but the implementation doesn't honor actions set from outside. It needs a bit of refactoring.

cobnet
10 Mar 2009, 7:12 AM
Great work Saki!

I am running into one issue, when changing:



,allowLeafAppend:true

.....................

,onNodeDragOver:function(e) {
if(true === this.allowLeafAppend) {
e.target.leaf = false;
}
} // eo function onNodeDragOver


if I change the allowLeafAppend:true to allowLeafAppend:false, nothing different seems to change? Am I missing something here? From what I understand this should show a "red circle with a line thru it" meaning you cannot put a leaf into a leaf on drag and drop. Am I correct here?
Thanks again,

jsakalos
10 Mar 2009, 7:33 AM
Does the data returned from the server contains leaf:true for that node?

cobnet
10 Mar 2009, 8:19 PM
Does the data returned from the server contains leaf:true for that node?

That was a very quick reply, :)

Partial json return:



..............{"text":"ExtJS Site","id":"l554","url":"http:\/\/extjs
.com","qtip":"ExtJS Site","cls":"file","leaf":"true"},{"text":"qWikiOffice","id":"l215","url":"http:
\/\/qwikioffice.com","qtip":"qWikiOffice","cls":"file","leaf":"true"}................


is this enough info?


EDITED: Ok, I changed my json return to read:



{"text":"ExtJS Site","id":"l554","url":"http:\/\/extjs
.com","qtip":"ExtJS Site","cls":"file","leaf":true},{"text":"qWikiOffice","id":"l215","url":"http:\/
\/qwikioffice.com","qtip":"qWikiOffice","cls":"file","leaf":true}


and now all is well, thanks for the quick and correct solution, you rock!

cobnet
12 Mar 2009, 2:46 PM
Saki,
I am studying at redoing the Bookmarks Module for the qwikioffice desktop using this extension and I have a few queries:

1) How is point determined? I see it can have the values: append and above, but looking at the js coding, I do not see "above" anywhere?

2) How is target determined? I see it probably does something according to what point is set to, but after that? Let's say the movenode cmd sends the following to the server:

point: above
target: somenumber

how is somenumber determined?

Any help would be greatly appreciated. I am hoping using this extension I can create a module that would work in both the qwikioffice and in a webpage using extjs without any changes. This may or may not happen, but I am studying the possibility of doing a module this way.

Again, thanks for sharing your work,
Mark

jsakalos
12 Mar 2009, 2:54 PM
Many, if not all, your questions are answered in TreeDropZone.js. I actually do nothing to determine target or point I get these values in event object e (created by Ext) that is argument to moveNode method.

cobnet
12 Mar 2009, 8:37 PM
Thanks again for the quick reply! ;)

I guess I did not word my query correctly, however I believe I am after something that I cannot have?

Consider the following:



[{"id":"1403","nodeID":"1403","pnodeID":"1","text":"ID 1403","leaf":false,"children":[{"id":"1404","nodeID"
:"1404","pnodeID":"1403","text":"ID 1404","leaf":true},{"id":"1408","nodeID":"1408","pnodeID":"1403"
,"text":"ID 1408","leaf":true},{"id":"1409","nodeID":"1409","pnodeID":"1403","text":"ID 1409","leaf"
:true}]}]

If I move one of the leafs inside the folder named ID 1403, I see that point will direct me to either "above" or "below" and the target will be the ID number of the leaf according to what point is in value.

On the server side of this, you will need to track where this leaf is in reference of ordering. I am looking for how you track the ordering of the leafs? I am guessing you cannot show this info? Obviously it is not by ID number?

EDITED: Let's say we have a database with fields corresponding to each of the above. Do I need to add an additional field titled: "Ordering" and change these values when a leaf is moved? By changing I really mean trade their values?

jsakalos
12 Mar 2009, 9:11 PM
Target is the node you dropped it on. If there is a point then it means: Not inside but above or below (=ordering). Of course you need a server side that is aware of ordering so simple parent-child relationship will not do. Neither ids nor names are used for ordering in my server side.

cobnet
12 Mar 2009, 10:09 PM
Thanks once more! I think I got it? I will update you when I have a working demo in place. B)

gipivak
20 Mar 2009, 4:08 AM
Hello,
I'm trying to use the extension, but I need to enable/disable context menu items based on a node's attribute (i.e node is leaf or not). I've modified the script in this part:


if(this.contextMenu) {
this.on({contextmenu:{scope:this, fn:this.onContextMenu, stopEvent:true}});
this.contextMenu.on({
hide:{scope:this, fn:function() {
this.actionNode = null;
}}
,show:{scope:this, fn:function() {
var node = this.actionNode;
var text = Ext.util.Format.ellipsis(node ? node.text : '', 12);
this.contextMenu.items.item(0).el.update(text);
this.contextMenu.el.shadow.hide();
this.contextMenu.el.shadow.show(this.contextMenu.el);
this.contextMenu.items.item(9)[node.isLeaf() ? 'enable' : 'disable']();
}}
});
}
but the disable method doesn't have effect. If I try to change the item's text with:

this.contextMenu.items.item(9).setText('newtext');
it works.
Is there something wrong with my code?
Thanks
Giampiero

jsakalos
20 Mar 2009, 5:10 AM
Have you ever read the documentation of RemoteTreePanel? Especially this: http://extjs.eu/docs/?class=Ext.ux.tree.RemoteTreePanel&member=actions

Why not to call:


remotetree.actions.reloadTree.disable();

?

gipivak
20 Mar 2009, 8:12 AM
Thanks for the quick suggestion, Saki.
I read the documentation but I guess I haven't enough Ext background to fully understand what you said.
Let's suppose I want to disable the context menu''s 'Rename Node' item if the node is a leaf.
Following your point I would have to call:

remotetree.actions.renameNode.disable(); ?
If yes where would I have to put the call? In a listener within my viewport (the remotetree is the west region of the viewport)?
Besides, referring to my previous attempt, why that context manu item is not actually disabled but the firebug shows it as disabled?

Many thanks
Giampiero



Have you ever read the documentation of RemoteTreePanel? Especially this: http://extjs.eu/docs/?class=Ext.ux.tree.RemoteTreePanel&member=actions

Why not to call:


remotetree.actions.reloadTree.disable();
?

jsakalos
20 Mar 2009, 8:19 AM
Generally, I don't know. You design the application so you need to figure out. If the clicked node has to be checked for decision on enabling/disabling actions then install an event handler e.g. beforeclick and do the job from the listener.

why that context manu item is not actually disabled but the firebug shows it as disabled
I have no idea what are you talking about. Before I posted my answer about calling rtp.actions.reloadTree.disable() I've tested it and after the call the item is disabled; it's grey and cannot be clicked.

queej
24 Mar 2009, 5:47 PM
Thanks for this really great extension, Saki.

I needed an "afterappend" event in the remotetreepanel so I can set up a mouseover and url for new nodes, etc. Thought this might be useful to other folks:



var o = Ext.apply(this.getOptions(), {
action:true === insert ? 'insertChild' : 'appendChild'
,node:childNode
,params:params
,success: function( response ) { this.fireEvent('afterappend',childNode,response); }
});
(There is also a line to add it to the list of events.)

It's about line 559, in the appendChild() method. Unlike the other events, it adds the server side response instead of the request.

Edit: changed from passing the tree to passing the childNode instead. Wasn't sure how/if fireEvent() could take more args or not.

jsakalos
24 Mar 2009, 6:20 PM
I've added a bunch of action + success events that fire when server returns success. See http://extjs.eu/docs/?class=Ext.ux.tree.RemoteTreePanel for details.

alex-t.de
31 Mar 2009, 1:28 AM
Hello,

I was just testing the last version of the RTP and I think there is a bug when using Safari. At the Moment I don't know if it is a general Ext problem.

Please look at the attached images.
1. image: right click on a tree node,
2. image: click on 'Insert' and look closely at the selected node from the 1. image, as you can see the selection disappeared.
3. image: the insert event created a new node as a child of root, but it should be the child of the selected node from the 1. image.

I suppose the selection goes away on clicking on the context menu. I there a work around for this?

In FF there is no such problem.

BTW: The RTP works great.

craig1980
31 Mar 2009, 2:22 AM
Hi Jsakalos,
I'd like to use your remotetree with java. I have downloaded source coded from this link (http://remotetree.extjs.eu/).
Do you have any suggestions about how I can implement my process-request.jsp?

I don't understand how process-request.php works because I don't know PHP language and how baseParams and processRequest communicate.

Regards Angelo

jsakalos
31 Mar 2009, 3:02 AM
@alex-tde, the first item of context menu (not clickable, bold) always shows the right-clicked node text. This indicates the target node of the operation (append, insert, rename, delete). It can be that the right-clicked node is not recognized in Safari.

BTW, I've just installed Safari 4 beta for Window$ and RTP works flawlessly in it.

jsakalos
31 Mar 2009, 3:05 AM
@craig1980, I don't use java so no idea. Nevertheless, you can analyze requests and responses in Firebug so you can know what is sent to server on, for example, node rename. Your server code just needs to understand the data received, execute the requested operation and return success or failure.

craig1980
31 Mar 2009, 3:26 AM
Thank jsakalos for the reply
I didn't think on this solution

I'll try and let u know.
Best regards
Angelo

alex-t.de
31 Mar 2009, 3:33 AM
@alex-tde, the first item of context menu (not clickable, bold) always shows the right-clicked node text. This indicates the target node of the operation (append, insert, rename, delete). It can be that the right-clicked node is not recognized in Safari.
...

I'm sorry for wasting your time. But the target node indicator makes sense.

I've testet RTP with the latest Webkit build, and it works!

queej
31 Mar 2009, 8:55 AM
My users needed some additional functionality in the context menu, including expand/collapse from the current node down, and copy & paste. I added this, in case anyone else can benefit:



,onExpandFromHere: function() {
this.selectedNode.expand( true, false );
}
,onCollapseFromHere: function() {
this.selectedNode.collapse( true, false );
}
,onCopy: function() {
var params = this.applyBaseParams();
params[this.paramNames.cmd] = this.cmdNames.copyNode;
params[this.paramNames.id] = this.selectedNode.id;
var o = Ext.apply(this.getOptions(), {
action:'copyNode'
,node:this.selectedNode
,params:params
});
Ext.Ajax.request( o );
}
,onPaste: function() {
var params = this.applyBaseParams();
params[this.paramNames.cmd] = this.cmdNames.pasteNode;
params[this.paramNames.id] = this.selectedNode.id;
var o = Ext.apply(this.getOptions(), {
action:'pasteNode'
,node:this.selectedNode
,params:params
});
Ext.Ajax.request( o );
}


You need to add other lines for the text, callbacks, etc., but they are nearly identical to what is already there for expandAll.

Do you think you might be interested in adding this functionality into your version, Saki? (Understanding that you would probably do a better job with the coding that what I am doing.)

jsakalos
31 Mar 2009, 9:08 AM
The existing operations are implemented as Actions so I expect that the above are only handlers of the new actions, right?

queej
31 Mar 2009, 10:37 AM
I think so, if I understand the terminology right. I added them to the list of Ext.Actions, along with the expandAll, etc.

Now that I'm looking at it more closely, its possible the Copy might be a client-side operation, whereas the Paste would make the server-side request using the last Copied tree id.

jsakalos
31 Mar 2009, 10:43 AM
Yes, that's what I've meant: Ext.Actions. You're also right regarding copy&paste.

queej
31 Mar 2009, 10:46 AM
This is a better copy/paste. It stores the last copy in a local property and then executes the server call only for pastes.



,onCopy: function() {
this.lastCopiedNode = this.selectedNode;
}
,onPaste: function() {
var params = this.applyBaseParams();
params[this.paramNames.cmd] = this.cmdNames.pasteNode;
params[this.paramNames.id] = this.selectedNode.id;
params[this.paramNames.target] = this.lastCopiedNode.id;
var o = Ext.apply(this.getOptions(), {
action:'pasteNode'
,node:this.selectedNode
,params:params
});
Ext.Ajax.request( o );
}

santail
1 Apr 2009, 8:53 AM
Is it possible to drop row-element from grid panel to tree and call the same events as tree nodes do ?
P.S. As I Understood, dropped tree element sends id and target values to controller. They are node Id, not an entity property 'id' ?
Thank you!

jsakalos
1 Apr 2009, 9:38 AM
That would need some changes because the current drop handler assumes that the drop is result of moving a node within the tree. You would need to append or insert the new node as the result of moving from the grid.

santail
2 Apr 2009, 1:00 AM
I'm pretty sure I have to di it :) But is there any samples how exactly implement this feature ? Do I have to override any of RemoteTree listeners ? I yes, then how ? Sorry, I'm novice in ExtJs.

jsakalos
2 Apr 2009, 2:03 AM
Yes, you'd need to override some RTP methods, for sure onBeforeNodeDrop. The logic has to decide if the dropped node comes from the tree internally or if it is a grid column.

BTW, if you're really novice, wouldn't it be better to take something simpler?

santail
2 Apr 2009, 5:31 AM
I've modified beforeNodeDrop listener with next code



,onBeforeNodeDrop:function(e) {

if(e.data.grid) {

var t = e.target;
var rindex = e.data.rowIndex;
var ds = e.data.grid.store;
var params = this.applyBaseParams();

for (i = 0; i < e.data.selections.length; i++) {
var insert = e.target.childNodes.length > 0 ? true : false;
params[this.paramNames.id] = e.data.selections[i].data.id;
params[this.paramNames.text] = e.data.selections[i].data.title;
params[this.paramNames.target] = e.target.id;
params[this.paramNames.point] = e.point;
params[this.paramNames.cmd] = true === insert ? this.cmdNames.insertChild : this.cmdNames.appendChild;

var o = Ext.apply(this.getOptions(), {
action:true === insert ? 'insertChild' : 'appendChild'
,params:params
});

if(false !== this.fireEvent('before' + (insert ? 'insert' : 'append') + 'request', this, o)) {
Ext.Ajax.request(o);
}
}
}
else {
this.moveNode(e);
}

e.dropStatus = true;
return false;

} // eo function onBeforeNodeDrop


Grid node became droppable onto tree panel and server side controller behaves properly: new tree nodes creation is successful. But I need more animated behavior - a need new tree node created in live when dropping process is finished.
Any help ?
Thank you !

P.S. How do I drop grid node onto empty treePanel where only hidden root node exists?

jsakalos
2 Apr 2009, 8:24 AM
Re animation: See how the existing tree/node animations are done, perhaps it helps.
Re empty panel: That shouldn't be problem if TreePanel has layout:'fit'

santail
2 Apr 2009, 11:57 PM
RTP control initialized in this mode:


var structurePanel = new Ext.ux.tree.RemoteTreePanel({
title:'Structure',
id:'siteStructure',
layout: 'fit',
autoScroll:true,
rootVisible:false,
enableDD:true,
ddGroup: 'gridToStructureDropZone',
lines: true,
selModel: new Ext.tree.MultiSelectionModel(),
root:{
nodeType:'async',
id:'isroot',
text:'root',
expanded:true,
uiProvider:false
}
});


But I can't drop grid row onto empty RTP, only onto tree node, above or below it. I did something wrong, didn't I ?

jsakalos
3 Apr 2009, 1:44 AM
Yes, I see where's problem. TreeDropZone is installed on tree.innerCt that is:


onRender : function(ct, position){
Ext.tree.TreePanel.superclass.onRender.call(this, ct, position);
this.el.addClass('x-tree');
this.innerCt = this.body.createChild({tag:"ul",
cls:"x-tree-root-ct " +
(this.useArrows ? 'x-tree-arrows' : this.lines ? "x-tree-lines" : "x-tree-no-lines")});
},


and if there is no visible node then height of this ul tag is 0.

wayned@escc
3 Apr 2009, 2:12 AM
Hey

What's the best way of adding nodes to the context menu from config?

I'd like to add some app specific nodes to the context menu but I'm finding it hard to figure out the best way of doing this.

w://

santail
3 Apr 2009, 2:28 AM
if there is no visible node then height of this ul tag is 0.

Sorry, but what should I do then ?

jsakalos
3 Apr 2009, 4:05 AM
Well, you have to solve it somehow. Another drop target on TreePanel::body? Adjust height of innerCt?

I've not done this before so I have no canned solution.

santail
6 Apr 2009, 8:41 AM
That is modified by me RemoteTreePanel that allows to drop GridPanel rows and produces ajax requests to server. Could you please check the code and maybe point me how to upgrade it if any errors present ?

Thank you!

jsakalos
6 Apr 2009, 9:06 AM
Does it work? If so there is no reason to check. Understand, I have no bandwidth to review user applications.

wayne_o
23 Apr 2009, 5:54 AM
this extension doesn't seem to work with 3.0 - do you have any plans to upgrade it?

w://

queej
23 Apr 2009, 9:37 AM
FWIW, I added the code below, borrowed mostly from mjoksa in this thread (http://extjs.com/forum/showthread.php?t=15383&page=2), to add statefulness to RemoteTreePanel. Not sure if you want to incorporate this into the official version, Saki, but it is helpful in my app.



// dqj - Added extension for statefulness below.
Ext.ux.tree.StatefulRemoteTreePanel = Ext.extend(Ext.ux.tree.RemoteTreePanel, {
//CookieProvider - hold state of TreePanel
cp: null,
//TreePanel state - simple array
expandedState: null,
//stateful option set to true
stateful: true,
/***** Events which cause TreePanel to remember its state
* click, expandnode, collapsenode, load, textchange,
* remove, render
********************************************************/
stateEvents: [{
click: {
fn: function(node) {
this.cp.set('LastSelectedNodePath_' + this.id, node.getPath());
this.cp.set('LastSelectedNodeId_' + this.id, node.id);
}
},
expandnode: {
fn: function(node) {
var currentPath = node.getPath();
var newState = new Array();

for (var i = 0; i < this.expandedState.length; ++i)
{
var path = this.expandedState[i];

if (currentPath.indexOf(path) == -1) {
// this path does not already exist
newState.push(path);
}
}

// now ad the new path
newState.push(currentPath);
this.saveState(newState);
}
},
collapsenode: {
fn: function(node) {
var closedPath = node.getPath();
var newState = new Array();

for (var i = 0; i < this.expandedState.length; ++i)
{
var path = this.expandedState[i];
if (path.indexOf(closedPath) == -1) {
// this path is not a subpath of the closed path
newState.push(path);
}
}

if (newState.length == 0) {
var parentNode = node.parentNode;
newState.push((parentNode == null ? this.pathSeparator : parentNode.getPath()));
}

this.saveState(newState);
}
},
load: {
fn: function(node) {
var lastSelectedNodePath = this.cp.get('LastSelectedNodePath_' + this.id);
var lastSelectedNodeId = this.cp.get('LastSelectedNodeId_' + this.id);

var rootNode = this.getRootNode();
if(node.id == rootNode.id) {
this.restoreState(this.root.getPath());
if(node.id == lastSelectedNodeId) {
this.selectPath(lastSelectedNodePath);
node.fireEvent('click', node);
}
return;
}

if(node.id == lastSelectedNodeId) {
node.fireEvent('click', node);
}
else {
var childNode = node.findChild('id', lastSelectedNodeId);

if(childNode && childNode.isLeaf()) {
childNode.ensureVisible();
this.selectPath(lastSelectedNodePath);
childNode.fireEvent('click', childNode);
}
else if(childNode && !childNode.isLeaf()) {
this.selectPath(lastSelectedNodePath);
childNode.fireEvent('click', childNode);
}
}
}
},
textchange: {
fn: function(node, text, oldText) {
var lastSelectedNodePath = this.cp.get('LastSelectedNodePath_' + this.id);
var newSelectedNodePath = lastSelectedNodePath.replace(oldText, text);

this.cp.set('LastSelectedNodePath_' + this.id, newSelectedNodePath);

this.expandPath(node.getPath());
this.selectPath(node.getPath());
}
},
remove: {
fn: function(tree, parent, node) {
this.cp.set('LastSelectedNodePath_' + this.id, parent.getPath());
this.cp.set('LastSelectedNodeId_' + this.id, parent.id);
}
}
}],

//Function which saves TreePanel state
saveState : function(newState) {
this.expandedState = newState;
this.cp.set('StatefulRemoteTreePanel_' + this.id, this.expandedState);
},

//Function which restores TreePanel state
restoreState : function(defaultPath) {
var lastSelectedNodePath = this.cp.get('LastSelectedNodePath_' + this.id);
var lastSelectedNodeId = this.cp.get('LastSelectedNodeId_' + this.id);

if (this.expandedState.length == 0) {
var newState = new Array(defaultPath);
this.saveState(newState);
this.expandPath(defaultPath);
return;
}

for (var i = 0; i < this.expandedState.length; ++i)
{
// activate all path strings from the state
try {
var path = this.expandedState[i];
this.expandPath(path);
}
catch(e) {
// ignore invalid path, seems to be remove in the datamodel
// TODO fix state at this point
}
}
},

initComponent: function() {
Ext.ux.tree.StatefulRemoteTreePanel.superclass.initComponent.call(this);

if(!this.cp) {
this.cp = lloom.cookieProvider;
}

if(!this.expandedState) {
var cookieState = this.cp.get('StatefulRemoteTreePanel_' + this.id);
if(!cookieState) {
this.expandedState = new Array();
}
else {
this.expandedState = cookieState;
}
}

if(!this.stateful) {
this.stateful = true;
}
}
});



(Edited to fix my previous incomplete paste.)

jsakalos
23 Apr 2009, 9:58 AM
Have you seen this example: http://examples.extjs.eu/?ex=treestate?

queej
23 Apr 2009, 10:06 AM
I looked at it, but that doesn't work with your RemoteTreePanel, so I thought I had to extend it. Is there a better way I could have done it?

Also, I have one more question. I am trying to get it so that only a double-click will trigger the editing of node names. Right now it triggers any time there is a second click, no matter what the interval between clicks. I read the docs on TreeEditor, and it says the default is 350ms, but that doesn't seem to be true. Any ideas on how I can get it to work only on a real double-click?

Thanks again.
-dqj

jsakalos
23 Apr 2009, 10:09 AM
Well, I'm using the very same plugin in my app with RTP and it does work. No idea (yet) what could be the problem in your case.

Re dblclick: I do nothing with it in RTP, do you think it can be a bug in Ext?

queej
23 Apr 2009, 10:14 AM
Jeepers, I missed seeing the plugin entirely. Sorry, must be getting tired. Will switch over to using that.

queej
23 Apr 2009, 10:28 AM
Can't get it to work yet, but I won't bother you with it. I'll take a fresh look again tomorrow.

jsakalos
23 Apr 2009, 11:25 AM
OK, crossing fingers. The first thing would be to replicate the example locally, then replace the example tree with RTP. Do not forget to include the plugin and also set it to tree's plugins array.

wayned@escc
28 Apr 2009, 1:02 AM
Any word on getting this to work for 3.0?

Sorry - but I upgraded to 3.0 and this is the only thing giving me grief because of the ctx menu.

Any help would be sooooooooooo appreciated :)

w://

jsakalos
28 Apr 2009, 6:12 AM
I have no own plans of upgrading RTP before Ext 3.0 final will be released. Only then I will port my really big app to Ext 3.0 and together with it all my extensions it uses.

dpommeranz
27 May 2009, 8:40 AM
Hi all,

I wanted to ask if there is a way to change the URLs for specific commands.

Example:

renameTreeNode should go to .../tree/rename/
moveTreeNode should go to .../tree/move/
...If there is no possibility I will override the desired functions.

Best Regards
D Pommeranz

jsakalos
27 May 2009, 8:56 AM
It won't work OOTB. What you could do:



,renameNode:function(node, newText) {

var params = this.applyBaseParams();
params[this.paramNames.cmd] = this.cmdNames.renameNode;
params[this.paramNames.id] = node.id;
params[this.paramNames.newText] = newText;
params[this.paramNames.oldText] = node.text || '';

var o = Ext.apply(this.getOptions(), {
action:'renameNode'
,node:node
,params:params
});
o.url = this.renameUrl ? this.renameUrl : o.url;
if(false !== this.fireEvent('beforerenamerequest', this, o)) {
// set loading indicator
node.getUI().beforeLoad();
Ext.Ajax.request(o);
}

} // eo function renameNode

dpommeranz
27 May 2009, 9:15 AM
Thanks for the quick reply. Will do it as you suggested then.

Regards
D Pommeranz

dpommeranz
28 May 2009, 12:33 AM
Just in case that somebody else wants to change the "action url's"...

I extended the RemoteTreePanel and changed some functions to support custom action url's:



,getOptions:function() {
return {
url:this.actionUrl || this.loader.url || this.loader.dataUrl || this.url || this.dataUrl
,method:this.loader.method || this.method || 'POST'
,scope:this
,callback:this.actionCallback
};
}
,appendChild:function(childNode, insert) {
this.actionUrl = null;
if ( true === insert ) {
this.actionUrl = '/certificatecategory/insert';
} else {
this.actionUrl = '/certificatecategory/append';
}
MyTree.superclass.appendChild.apply( this, arguments );
}
,moveNode:function(e) {
this.actionUrl = null;
if ( e.dropNode.attributes.type == 'category' ) {
this.actionUrl = '/certificatecategory/move';
} else if ( e.dropNode.attributes.type == 'certificate' ) {
this.actionUrl = '/certificate/move';
} else {
return;
}
MyTree.superclass.moveNode.apply( this, arguments );
}
,removeNode:function(node) {
this.actionUrl = null;
if ( node.attributes.type == 'category' ) {
this.actionUrl = '/certificatecategory/remove';
} else if ( node.attributes.type == 'certificate' ) {
this.actionUrl = '/certificate/remove';
} else {
return;
}
MyTree.superclass.removeNode.apply( this, arguments );
}
,renameNode:function(node, newText) {
this.actionUrl = null;
if ( node.attributes.type == 'category' ) {
this.actionUrl = '/certificatecategory/rename';
} else if ( node.attributes.type == 'certificate' ) {
this.actionUrl = '/certificate/rename';
} else {
return;
}
MyTree.superclass.renameNode.apply( this, arguments );
}
Regards
D Pommeranz

jsakalos
28 May 2009, 12:42 AM
Thank you for sharing. If there are more users requiring the separate action urls, I'll add it to the core code.

wayned@escc
1 Jul 2009, 7:31 AM
Any plans for an Ext 3 version yet ? :)

jsakalos
1 Jul 2009, 8:48 AM
Any problems with Ext 3?

queej
3 Aug 2009, 6:34 AM
I have a problem only with the contextMenu in 3.0. The call to menu.getEl() fails, and the line:

this.contextMenu.items.item(0).el.update(text);

is also failing. Have been trying to fix it, but without success so far. Will post fix if I can find it.

queej
3 Aug 2009, 7:04 AM
Rather than using the menu.getEl() and aligning coordinates based on that, I switched to using:

menu.showAt([e.getXY()[0], e.getXY()[1]]);

This may not be the best way, but it does fix the context menu issue that happens in 3.0. I can't give line numbers because my copy of RemoteTreePanel is highly customized. (Pretty sure the context menu issue is common, however, because it was mentioned in this thread previously.)

jsakalos
3 Aug 2009, 12:25 PM
Yes, menu changed in Ext 3 - I'll need to find "final" fixes for that. Glad that your patches work for you.

wayned@escc
24 Aug 2009, 2:51 AM
I tried adding the fix above but now I get a problem on the following line:


this.contextMenu.items.item(0).el.update(text);


this.contextMenu.items.item(0) is not defined.

looks like all the items are at the root of the object so this.contextMenu[0] works but not this.contextMenu[0].el

is there going to be a fix for this ux anytime? we used it in production and now can't - so have had to make a rather shoddy work around.

I've tried getting it to work by doing various things but get an empty menu showing?

w://

wayned@escc
24 Aug 2009, 5:49 AM
Easy fix:



// create context menu
if(true === this.editable && true === this.contextMenu) {
this.contextMenu = new Ext.menu.Menu({
items: [
new Ext.menu.TextItem({text:'', style:'font-weight:bold;margin:0px 4px 0px 27px;line-height:18px'})
,'-'
,this.actions.reloadTree
,this.actions.expandAll
,this.actions.collapseAll
,'-'
,this.actions.expandNode
,this.actions.collapseNode
,'-'
,this.actions.renameNode
,'-'
,this.actions.appendChild
,this.actions.insertChild
,'-'
,this.actions.removeNode
]
});
}


note the

items:
part

SIMPLES!!

w://

jsakalos
24 Aug 2009, 11:06 PM
Thank you very much for finding and providing the fix.

buzux
11 Sep 2009, 6:08 AM
Hi,

Despite the patch I have the following error when I do a right click on the tree:


menu.getEl() is undefined
var xy = menu.getEl().getAlignToXY(alignEl, 'tl-tl', [0, 18]);\nUbuntu 8.04, FF 3.0.14, Ext JS 3.0.1

jsakalos
11 Sep 2009, 2:18 PM
I've tested with latest svn and if I replaced [] with items:[] in the context menu config then it worked.

tonedeaf
26 Sep 2009, 5:31 AM
I've tested with latest svn and if I replaced [] with items:[] in the context menu config then it worked.
I get the same error msg "this.contextMenu.on is not a function" when I try to create a RemoteTreePanel with editable: false in the config object.
I applied all the fixes outlined in the previous posts. The Remote Tree Panel works correctly if I specify editable: true in the config options.
Tested in ExtJS 3.0.0 in Firefox.

farracha
6 Oct 2009, 9:14 AM
Hi Saki,

First, let me thank you so much for all your knowledge that you share.

Now my doubts :)

1- I assume that your remote tree doesn't show checkboxes right? I sent checked attribute on json data, and no checkboxes were rendered!

2- I know that you developed a CheckTreePanel. The behaviour is the same from remotetree? What I need to know is if I can use a context menu (remotetree) on this type of tree.

3- I found the remotetree filter too slow. The browser hangs up. Not so much on Firefox (maybe 5seconds), but definitely on IE7. I have 940 nodes (15 main parents, and lot of childs and 2nd-childs, 3rd-childs...). Is there a way to improve the search? I altered the filter to search only when at least were typed 4 letters, but no improvement. Because the filter the first time has to search all tree :(

Thanks in advance.

jsakalos
7 Oct 2009, 4:15 AM
1 & 2 - the purposes are different: RemoteTree: to edit tree, CheckboxTree: to select nodes
3. quite a lot of nodes... I haven't optimized anything for such a lot...

farracha
7 Oct 2009, 5:03 AM
Hi,

Hmmm but it's fairly easy to add a contextmenu on checktreepanel? If I "merge" the source code from remotetree and checktreepanel, I would manage to get it working without too much trouble, for a newbie (medium javascript understanding)?

3- I was afraid that the rendering would be slow, but after all, the filter turned out to be the problem. I guess that I will perform a custom filter, that will be loading/rendering the tree again but filtered on the database.

cchain
3 Nov 2009, 1:00 PM
Saki - GREAT extension! You've saved me a lot of work.

I'm attempting to change the default textfield editor to a textarea, since my application needs more "breathing room" for editing. For some reason, the width attribute is not being honored...

Here is my config for the tree so far (I haven't needed to modify the extension code at all):



accred.tree = new Ext.ux.tree.RemoteTreePanel({
id:'remotetree'
,autoScroll:true
,rootVisible:true
,allowLeafAppend:false
,editorFieldConfig:new Ext.form.TextArea({
allowBlank:false
,width:600
})
,root:{
nodeType:'async'
,id:'0'
,text:'Accreditation'
,expanded:true
,uiProvider:false
}
,loader:{
url:'content/accred/qry_accredform.cfm'
,preloadChildren:true
,baseParams:{
cmd:'getTree'
,treeTable:'so_accred_items'
,treeID:1
}
}
});
I see the textarea, and it updates properly, but it seems to be locked to 242 pixels in width. Any suggestions?

Also, the next step for me is to build a form below the tree that gets the node data (or loads it via an AJAX call) when the node is selected in the tree. I'm still very much an Ext n00b, so any assistance pointing me in the right direction would be greatly appreciated. :D

Thanks!

jsakalos
4 Nov 2009, 4:32 AM
I think that Ext automatically sizes the tree editor to the width of tree. Take a look at Ext code.

cchain
4 Nov 2009, 11:51 AM
Got it. New day, new perspective.

Thanks for pointing me back to the docs Saki, the answer was there.

I added:



,editorConfig:{maxWidth:792}
to the tree config, and it works great.

Any suggestions for the form I need to build that I mentioned in my initial post?

jsakalos
5 Nov 2009, 2:38 AM
Listen to selectionchange (http://www.extjs.com/deploy/dev/docs/?class=Ext.tree.DefaultSelectionModel&member=selectionchange) event and fill in the form from the listener.

cchain
6 Nov 2009, 9:58 AM
This is working for me now:



// tree node select listener
nav.tree.on('click',function(node){
nav.form.load({
params:{cmd:'getNodeDetail',id:node.id}
,url:'content/editors/nav/qry_navEditor.cfm'
});
});
Is there a particular reason I should use selectionchange as opposed to click?

I tried replacing click with selectionchange in the code above, but it didn't work...

jsakalos
7 Nov 2009, 6:54 AM
Click fires everytime you click, selectionchange fires only when selection changes. BTW, selectionchange is event of SelectionModel not of TreePanel - that is most likely the reason why it didn't work for you.

cchain
16 Nov 2009, 11:14 AM
Using code I found in remoteTreePanel.js, I modified the code to this:



// tree node select listener
voa.tree.getSelectionModel().on({
selectionchange:{
scope:this, fn:function(selModel, node){
accred.form.load({
params:{cmd:'getNodeDetail',id:node.id}
,url:'content/accred/qry_accredform.cfm'
});
}
}
});


Seems to work just fine. Hopefully someone else can benefit from this... often times, I just need a code example to see how to apply the suggestions provided.

Saki, thanks for your help!

jsakalos
16 Nov 2009, 1:23 PM
Thank you for sharing that - can be useful for others.

cchain
11 Dec 2009, 3:00 PM
I need the ability to programmatically set the editable property, ideally something like setEditable(false).

Any suggestions how I could modify to the code to add this method?

jsakalos
12 Dec 2009, 8:34 AM
Setting tree.editable = false should be enough.

cchain
14 Dec 2009, 3:00 PM
...and of course, it works. Thanks again for the direction. :D

extjs_new
25 Dec 2009, 10:39 PM
Hi jsakalos, hi everyone

I wanted to have a form to appear everytime the Insertion of node is triggered (for both append and insert). That form would have a textbox, a lookup button, a resulting grid, an OK and close button.
It will then search for the either ID or the person name from a database.

After a selection have been made it would return the selected ID and the person name back to the RTP then continue with the onAppendChild function.

how could I accomplished this? Thank you.

jsakalos
27 Dec 2009, 9:09 AM
You need to have a listener that would intercept the event(s) and that would implement the functionality you describe above.

extjs_new
30 Dec 2009, 3:12 AM
Hi Saki, using your example http://examples.extjs.eu/?ex=grid2treedrag
I tried to create a function that will allow to have drag source from the grid.
At my PHP code it will handle the Insertion of New appended Node
I am not sure If I got the correct logic here.

But in my javascript, I have a problem at the portion: e.dropNode.getUI().beforeLoad();


,InsertAppendMoveNode:function(e) {


var params = this.applyBaseParams();
params[this.paramNames.cmd] = 'InsertAppendMoveNode';
params[this.paramNames.target] = e.target.id;
params[this.paramNames.point] = e.point;


// e.data.selections is the array of selected records
//though I have set my selModel of my grid as singleSelect only
if(Ext.isArray(e.data.selections)) {
// reset cancel flag
e.cancel = false;

// setup dropNode (it can be array of nodes)
e.dropNode = [];
var r;
for(var i = 0; i < e.data.selections.length; i++) {

// get record from selectons
r = e.data.selections[i];
params[this.paramNames.id] = r.get('id');
params[this.paramNames.text] = r.get('company');

// create node from record data
e.dropNode.push(this.loader.createNode({
id:r.get('id')
,text:r.get('company')
,leaf:true
}));

var o = Ext.apply(this.getOptions(), {
action:'InsertAppendMoveNode'
,e:e
,node:e.dropNode
,params:params
});



if(false !== this.fireEvent('beforeinsertrequest', this, o)) {
// set loading indicator
//This is my problem at this point
//how can we detect the dropNode.getUI().beforeLoad(), since its from a gridpanel and does not have a dropNode properties
e.dropNode.getUI().beforeLoad();
Ext.Ajax.request(o);


} //if(false !== this.fireEvent('beforemoverequest', this, o)) {


} // for(var i = 0; i < e.data.selections.length; i++) {



// we want Ext to complete the drop, thus return true
return true;
}
}How would I resolve at the line saying e.dropNode.getUI().beforeLoad();
since the drag Source is from a gridpanel and not from a TreePanel?
Or does anyone have an example of a RTP that accepts a dragsource from a gridPanel? ... the GridPanel data will not be removed from the gridpanel when drag.

jsakalos
30 Dec 2009, 12:55 PM
You just need to take the arguments from DragSource and process them according to the drop you are handling. I know, this sounds too general, anyway, with the help of Firebug, you can do it quite easily. See what drag data you have, see what drop target requires and process it accordingly.

extjs_new
31 Dec 2009, 1:40 PM
Hi Saki, thanks alot,

How can I reverse this?


e.dropNode.push(this.loader.createNode({
id:r.get('id')
,text:r.get('company')
,leaf:true
}));I wanted to remove that particular node that I've just dropped into RTP (source drag from gridPanel)
if at my PHP return unsuccessful insertion in the database. Thanks

jsakalos
2 Jan 2010, 4:42 PM
I don't quite get what do you want to do. If you want to remove node just call the appropriate method (remove or removeChild). You just need a reference to the to-be-removed node.

cchain
18 Jan 2010, 12:03 PM
I know, Saki, that you've said that your server backend for processing the tree instructions is proprietary, so I'm putting this out to the other folks using RemoteTreePanel...

I've had no problems putting together the necessary SQL for all of the tree commands except for MoveTreeNode. The code I have is so convoluted and complicated that I keep thinking there must be a better way. It's so bad that I'm embarrassed to even post it here...

I would like to see how others have implemented their MoveTreeNode processing.

Here's how my DB table is set up:


[id] numeric primary key
[itemlevel] numeric level of items in tree structure (1 is top level, 2 is child of 1, etc.)
[parent] numeric id of parent item (if item is NOT at top level, otherwise NULL)
[sortorder] numeric sort order (starting at 0)
[description] the "name" of the itemI'm using SQL Server 2005 and ColdFusion if that makes any difference to anyone. I'd really appreciate everyone's insights on this.

jsakalos
18 Jan 2010, 4:12 PM
Try to find another way of saving tree-like structure in a db table. Maybe parent and sortorder work, however, there are better ways.

cchain
19 Jan 2010, 8:42 AM
I wish you could give more detail... maybe I'm too close to the problem to see outside of it.

I looked at the example on your site, I see you are using pnodeID, which stores the numeric ID of the parent node. This is the same way I am doing it with the parent column, unless you are doing some trickery on the SQL side to generate the JSON response that way... is the children column actually a real column, or generated by the query?

jsakalos
19 Jan 2010, 10:34 AM
pnodeID is only auxiliary. google for the topic, I'm sure you'll find something.

cchain
20 Jan 2010, 10:09 AM
Okay Saki, so what is your preference:



Adjacency Model (I know this isn't it, because that's what I've been using)
Nested Set
Materialized Path
Nested Interval


I found a wealth of info on tree structure out there, but I'm curious what you're using. So far, my applications have not needed terribly large trees (less than 100 nodes), but the latest one I'm working has the potential to get to several hundred nodes, so performance is going to be a key point.

Hopefully, having names for some of these models will help others in their search for a good way to represent tree data... below are a few articles that discuss the different methods that I found useful:

http://articles.sitepoint.com/article/hierarchical-data-database#

http://www.dbazine.com/oracle/or-articles/tropashko4

http://intelligent-enterprise.informationweek.com/001020/celko1_1.jhtml

jsakalos
21 Jan 2010, 1:54 AM
Nested Set.

PHaroZ
16 Feb 2010, 8:12 AM
Hi,

Since the Ext 3x version I got problems with a part of your extension.

In the onContextMenu function there is an error at the line :


var xy = menu.getEl().getAlignToXY(alignEl, 'tl-tl', [0, 18]);menu.getEl() returns null.

In Ext 2.2.1 I don't have any problems.

Do you have an idea or a fix ?

Thx.

jsakalos
16 Feb 2010, 8:24 AM
if(!menu.rendered) { // new
menu.render(); // new
} // new
var xy = menu.getEl().getAlignToXY(alignEl, 'tl-tl', [0, 18]);

PHaroZ
16 Feb 2010, 11:46 PM
Thx a lot !

sharkcap
20 Feb 2010, 1:08 PM
I need to customize this example a little. I want to trigger an event when i click on each individual folder.

I figure it probably ought to be added in the Ext.ux.tree.RemoteTreePanel.js file, but my playing around alittle hasn't yielded the right result.

I think I'll be fine on my own once I (or someone here) can help me figure out how I can just produce a simple

alert('node: '+ nodeID + 'was clicked');
on the click of any/each folder

Thanks
Andrew

batweasel
6 Apr 2010, 4:56 AM
Hello

This is my very first post here.

RemoteTreePanel Drag and Drop reordering was not working for me in Ext JS 3.1.1. The dragged node ended up always as the last node of it's parent node despite the drop position.
Since I spent half a day finding the fix I decided to post it here.

NB! I am not sure if this fix will or will not brake any other functionality in the component so be careful.

Just add

options.e.target.parentNode.childrenRendered = false;
before the line

this.dropZone.completeDrop(options.e);

jsakalos
6 Apr 2010, 6:20 AM
Upgrade to Ext 3.2.0 or 3.1.2. There was a bug in 3.1.1. No modification of RTP is needed.

Maxrunner
12 Apr 2010, 10:08 AM
Hi! i was wondering if someone might now how to manually drop a node. i know this is isnt the right place but seeing this plugin actually does that i was wondering if i could do it since there's some urge. Here's my simple beforenodedrop event:


tree.on('beforenodedrop',function(dropEvent){

Ext.Ajax.request({
method: 'POST',
params:{
Dragged:dropEvent.dropNode.id,
NewParent:dropEvent.target
},
url: 'some url',
sucess:function(response, opts){
///complete drop here
}
});
dropEvent.cancel=true;
});

The idea was to drop the node in the sucess property of the ajax request.

mohan_b
12 Apr 2010, 12:08 PM
Hi Jozef Sakalos,

RTP is a Great plugin

I would like some assistance in building a plugin which has all the functionalities from RTP as well as from the TreeGrid(Ext.ux.tree.TreeGrid).. please let me know how do I go about making such a plugin. I will post and maintain the plugin onto the Ux plugins forum once its done.

Thanks for your and everyones efforts/suggestions. All efforts will be acknowledged in the plugin's description.

jsakalos
12 Apr 2010, 12:11 PM
I have not other code than that what is in RTP. Take it and modify it for your needs.

sharkcap
27 Apr 2010, 6:39 PM
I am using the remoteTree and it will always have at least 4 folders at the top level; so what I've done is set rootVisible to false.
so I see 'folder1','folder2','folder3','folder4' at the top level.

now lets say I access the tree via a page like index.cfm?folder=2...
How can I load the page with 'folder2' selected onload?

please look at my code below and notice that:
console.log( Example.tree.getRootNode().firstChild ); it returns NULL

If I put in my code:
Ext.getCmp('remotetree').getRootNode().firstChild.select(); it errors because it's NULL

This dilemma is really just holding me back from what i really want. For now, I can't get the firstChild to be selected onload; but really i want is to have a node selected onload based on getting the NodeID from a URL parameter.

How can i accomplish this?





Example.tree = new Ext.ux.tree.RemoteTreePanel({
id:'remotetree'
,autoScroll:true
,frame:false
,renderTo:'prodTree'
,rootVisible:false
//,title:Ext.get('page-title').dom.innerHTML
,root:{
nodeType:'async'
,id:'root'
,text:'Root'
//,rootVisible:false
,expanded:true
,uiProvider:false
}
/*,listeners:{
click:{
fn:clickListener
}
}*/
,loader: {
url:'/remotetree/process-request.cfm'
,preloadChildren:true
,baseParams:{
cmd:'getTree'
,treeTable:'tree'
,treeID:1
}
}
,tbar:['Filter:', {
xtype:'trigger'
,triggerClass:'x-form-clear-trigger'
,onTriggerClick:function() {
this.setValue('');
Example.tree.filter.clear();
}
,id:'filter'
,enableKeyEvents:true
,listeners:{
keyup:{buffer:150, fn:function(field, e) {
if(Ext.EventObject.ESC == e.getKey()) {
field.onTriggerClick();
}
else {
var val = this.getRawValue();
var re = new RegExp('.*' + val + '.*', 'i');
Example.tree.filter.clear();
Example.tree.filter.filter(re, 'text');
}
}}
}
}]
});

/*clickListener = function (node,event){
alert('I was clicked');
}*/

Example.tree.filter = new Ext.ux.tree.TreeFilterX(Example.tree);

//console.log( Example.tree.getRootNode().getUI());
console.log( Example.tree.getRootNode().firstChild);

jsakalos
28 Apr 2010, 8:10 AM
Most likely you call it too early, before children are loaded.

sharkcap
28 Apr 2010, 7:03 PM
From where would i call it from that would be after the children are loaded?
Ive tried in various places throughout the remotetree.js and Ext.ux.tree.remotetreepanel.js file with no luck.

And my second question was lets say I knew the node i wanted selected was node:48 (for example) rather than the firstChild, how could I default that as selected?

Thanks, Andrew

jsakalos
29 Apr 2010, 1:58 AM
You see, this is asynchronous tree what means that it is not fully loaded initially. As user clicks folders, they are loaded on demand. Therefore, you must first programmatically load the branch you want selected and after it is loaded you can select the node. Take a look at expandPath and selectPath methods of TreePanel.

sharkcap
15 May 2010, 7:42 PM
Thanks for your help Saki,
I have the portion of my app near completion that makes use of the asynchronous tree. I have it working just fine if it runs in just one page, for example /index.cfm.



Note that index.cfm has the js in head tag:


<script type="text/javascript" src="/remoteTree/js/Ext.ux.form.ThemeCombo.js"></script>
<script type="text/javascript" src="/remoteTree/js/Ext.ux.menu.IconMenu.js"></script>
<script type="text/javascript" src="/remoteTree/js/Ext.ux.Toast.js"></script>
<script type="text/javascript" src="/remoteTree/js/Ext.ux.tree.TreeFilterX.js"></script>
<script type="text/javascript" src="/remoteTree/js/Ext.ux.tree.RemoteTreePanel.js"></script>
<script type="text/javascript" src="/js/remotetree.js"></script>
<script type="text/javascript" src="/js/EXT/ux/DataView-more.js"></script>
<script type="text/javascript" src="/js/EXT/data-view.js"></script>
but I have decide that for my application, i would prefer to have a button clicked within the index.cfm, which opens a new ext window that loads /popup.cfm, which as /popup.cfm loads after the button is clicked from index.cfm it calls my showTreePanel() function below

firebug throws me this error: Ext.ux.menu is undefined
but it should be defined, because <script type="text/javascript" src="/remoteTree/js/Ext.ux.menu.IconMenu.js"></script>
loads in the head of index.cfm before <script type="text/javascript" src="/js/remotetree.js"></script>

if you know off the top of your head why i might get this this error, i would appreciate a nudge in the right direction.


showTreePanel = function(){

//function showTreePanel(){
Ext.QuickTips.init();

var win = new Ext.Window({
id:'gswin'
,iconCls:'icon-expand'
,width:300
,height:400
,x:400
,y:220
,plain:true
,layout:'fit'
,closable:false
,border:false
,maximizable:true
,items:Example.tree
,tools:[{
id:'refresh'
,handler:function() {
win.items.item(0).actions.reloadTree.execute();
}
}]
,plugins:[new Ext.ux.menu.IconMenu()]
});

jsakalos
15 May 2010, 10:46 PM
Add Ext.ns('Ext.ux.menu') somewhere at the beginning of the code.

Androsx5
21 May 2010, 1:38 AM
Hello to everybody,

this is a request to jsakalos. I need the files pertaining Ext.ux.tree.RemoteTreePanel php 4 classes that implement the operations on the tree.

Can you help please?

I would need for my thesis but time plays against me, this is my last thing to do. I would also like to pay.. Let me know

bye bye

jsakalos
21 May 2010, 1:42 AM
Sorry, the server-side is proprietary so I cannot publish it.

Androsx5
21 May 2010, 1:48 AM
I can image, I tried to ask because I'm so tired after 3 mounths of work. Thanks the same, I'll do it alone!!

extjs_new
31 May 2010, 2:13 AM
[QUOTE=cchain;409192]Using code I found in remoteTreePanel.js, I modified the code to this:



// tree node select listener
voa.tree.getSelectionModel().on({
selectionchange:{
scope:this, fn:function(selModel, node){
accred.form.load({
params:{cmd:'getNodeDetail',id:node.id}
,url:'content/accred/qry_accredform.cfm'
});
}
}
});



Hi cchain, can you help me,
How can I show a form after the user click one the menu, (says when the user click the rename menu).

PaulyWolly
8 Jun 2010, 3:51 PM
Saki,

I notice that in other threads you have posted other code (FileTree - for example) where you have extensive backend functionality, you note that you will give the back-end code for a fee. Is this option available as well for the RemoteTree backend as I am in need of a process similar to this? :-/

jsakalos
8 Jun 2010, 4:53 PM
Contact me on Skype on the matter please.

imnphd
10 Jun 2010, 7:30 AM
Does this panel work in Ext 3.2.1?

I am getting this error when I try the example:

menu.getEl() is undefined
var xy = menu.getEl().getAlignToXY(alignEl, 'tl-tl', [0, 18]);

jsakalos
10 Jun 2010, 12:13 PM
I've tested it right now against Ext-3.2.2 and it works - no errors.

jamie0725
22 Jun 2010, 4:41 AM
Hi,

I am trying to extend RemoteTreePanel as I want a different behavior for onBeforeNodeDrop and also want to avoid changing the code in Ext.ux.tree.RemoteTreePanel.js

When I try to extend it "the usual way" I get "Ext.ux.tree is undefined" from Firebug. Creating an instance of Ext.ux.tree.RemoteTreePanel with "var foo = new ..." works.



Ext.namespace('Application');
Application.CategoryTree = Ext.extend(Ext.ux.tree.RemoteTreePanel,
{
//
});Any hint what's wrong?

Thanx,
J.

jamie0725
22 Jun 2010, 4:45 AM
I had this problem as well, but noticed another posting where you recommended some changes like that. This change is not in the code you can download at the moment at remotetree.exjs.eu:



var alignEl = node.getUI().getEl();
if(!menu.rendered) { // new
menu.render(); // new
} // new
var xy = menu.getEl().getAlignToXY(alignEl, 'tl-tl', [0, 18]);



I've tested it right now against Ext-3.2.2 and it works - no errors.

jsakalos
22 Jun 2010, 6:21 AM
Your extension must come after Ext.ux.tree.RemoteTreePanel.

jamie0725
21 Jul 2010, 8:35 AM
Ext.namespace('Application');
Application.CategoryTree = Ext.extend(Ext.ux.tree.RemoteTreePanel,
{
//
});
Your extension must come after Ext.ux.tree.RemoteTreePanel.

Sorry, what do you mean by this?

J.

jsakalos
21 Jul 2010, 8:47 AM
The order in which you include individual javascript files in page <head></head>.

koucz
6 Aug 2010, 1:49 AM
Hello

When I try insert a new node by contextmenu (rightclick on the mouse),
first rightclick and choise insert, add new node by rootnode,
but second rightclick , add the new node corectly.

Why the first click doesn't work corectly ?

pleae look at http://kolos.math.uni.lodz.pl/~tommy/ext/ext/

jsakalos
6 Aug 2010, 2:54 AM
I cannot reproduce it at the link you've posted. Everything works as expected in Safari@Mac.

koucz
6 Aug 2010, 5:12 AM
Upps I put console.info(node) in function onContextMenu


:function(node, e) {
var menu = this.contextMenu;
console.info(node);
I turn it off.

Please check again.

Please try to add (insert) new node by contextmenu.

jsakalos
6 Aug 2010, 11:53 AM
Still no problem, Append and Insert from context menu work like expected. BTW, can you reproduce the problem on my site of RTP?

jpgilman
30 Sep 2010, 9:26 AM
FWIW, I think I can recreate koucz's error both on his site and in our application, but not on your site. I don't see the issue using Safari. To see the issue use Firefox with Firebug Console enabled. Refresh the tree and then right click on a node. The first and only the first right click generates the following error:

menu.getEl() is undefined
http://kolos.math.uni.lodz.pl/~tommy/ext/ext/ux/Ext.ux.tree.RemoteTreePanel.js
Line 708

jsakalos
30 Sep 2010, 11:39 AM
It seems that menu is not rendered at the time of the error. There is no getEl() in line 708. There is getEl() around line 1475 and it is sure that menu does exist at that point. Which version are you using?

fabiojpoli
31 Oct 2010, 11:03 AM
Hello, great job!

But I have an exception in my application. The nodes of the tree are all like 'hidden: true' and I will I display (show ()) according to the user's permission. Assuming the user has access to node A, B and C, and has no access to node D, the filter with a word with any treeFilter exhibit the children of node D, which is the node that it has no access.

I wish that, when the user types the word to search, browse only the nodes that can be displayed to that user.

How to solve this exception?

Thanks!

jsakalos
31 Oct 2010, 3:09 PM
Either not deliver that nodes from the server at all or implement some permissions logic that would do that.

fabiojpoli
6 Nov 2010, 8:03 AM
only solution


this.storeModulosUsuario = new Ext.data.JsonStore({
autoLoad: true,
url: 'include/administracao/moduloAction.php?action=listarModulosUsuario',
root:'rows',
fields: [{name: 'id_fonte'}],
listeners: {
scope: this,
load: function(store){
var rootNode = this.menuAjuda.getRootNode();
store.data.each(function(item){
var menu = item.get('id_fonte') + 'Help';
rootNode.findChild('id', menu).ui.show();
})

this.menuAjuda.getRootNode().eachChild(function(n){
if(n == undefined || n == null){}
else if(n.hidden === true)
n.remove(true);
});
}
}
});

cchain
11 Nov 2010, 10:21 AM
I've seen a lot of questions posted on this thread regarding how to implement RemoteTreePanel with your back end... I know I have struggled with this as well, and the first solution I came up with was definitely not an optimal one.

Recently, I put a considerable amount of time and effort into writing proof-of-concept code for a redesign of our website's navigation menu system. Once I had a working test environment, I realized that I should share what I came up with so other people might benefit and learn from it.

I put together this demo that includes a fully functioning back end written in CFML using MS SQL Server for the database and a Nested Set model for storing the data. It's stripped down and simplified so that it should be fairly easy to follow the queries that make each tree operation work.

The demo code is released under the GNU LGPL, full documentation and instructions are in the index.html. I have also included plenty of reference links to dive more deeply into the data model, should you wish to do so.

Hope this helps some of you who may be struggling.

extjs_new
27 Nov 2010, 1:01 AM
You need to have a listener that would intercept the event(s) and that would implement the functionality you describe above.

Hi Saki,

My RTP is an item inside my window panel.
I have another window that will display node details, which will be shown upon a custom event (say viewPropertyNode) from RTP
Im not using any viewport. Where would I put my listener (relayEvents)?
Should I just create a hidden panel that is present at all time:

myHiddenPanel.relayEvents(myRemoteTreePanel,['viewPropertyNode']);

Or use Observable?

Thanks,

jsakalos
30 Nov 2010, 9:46 AM
This is too specific for your app I know nothing about so I cannot say anything helpful. Anyway, I've written an article on events (http://blog.extjs.eu/know-how/events-explained/).

c.barca
9 May 2011, 8:22 AM
Ext.ux.tree.RemoteTree remove items from ContextMenu


Hi,

for my app I need deny some operations from ContextMenu on Ext.ux.tree.RemoteTree.
I don't modify the extension because all operations are permitted on other part on my web app.

Can I remove some items from ContextMenu by external Config ?

I tried using the missing parameters 'actions' but don't run
In effect on doc there is
/**
* @cfg {Object} actions Public interface to methods of tree operations. Actions are created internally
* and then are available for user space program. Actions provided from outside at instatiation time
* are honored.
*/

how to ?

Thank's all

Claudio Barca

rmichelli
12 Jun 2011, 6:11 PM
Hello all,
Wonderful plugin - one of my favorites.
We're porting an application from 2.3 to 3.3.3 and finally got around to implementing an external menu config for this plugin. This mod creates an optional menuItemCfg which allows one to externally set specific actions to include in the menu. See the comment code block for how to use. This code was developed for and tested with 3.3.3 but should be compatible with 2.3 (change Ext.isString(item) to typeof item == 'string').

Example - menuItemCfg: ['renameNode', '-', 'insertChild', '-', 'removeNode']
26560

Mods required are:

Comments:

/**
* @cfg {Array} menuItemCfg (optional) Config which will be used as the 'items' config for the context menu. May contain
* standard menu items or strings of action names. Action names will be replaced with the specified action.
* Note: The standard node text display item will always the first in the menu
* Example: menuItemCfg: ['renameNode', '-', 'insertChild', '-', 'removeNode']
*/In initComponent, change:

var config = {};to:

var config = {}, menuItemCfg = this.initialConfig.menuItemCfg; delete this.initialConfig.menuItemCfg;Also in initComponent, directly under the 'create context menu' comment, replace the if statement with:

if(true === this.editable && true === this.contextMenu) {
if(menuItemCfg) {
Ext.each(menuItemCfg, function(item, index) {
if(Ext.isString(item) && this.actions[item]) {
menuItemCfg[index] = this.actions[item];
}
}, this);
}
else {
menuItemCfg = [
this.actions.reloadTree
,this.actions.expandAll
,this.actions.collapseAll
,'-'
,this.actions.expandNode
,this.actions.collapseNode
,'-'
,this.actions.renameNode
,'-'
,this.actions.appendChild
,this.actions.insertChild
,'-'
,this.actions.removeNode
];
}
menuItemCfg.unshift(new Ext.menu.TextItem({text:'Item', style:'font-weight:bold;margin:0px 4px 0px 27px;line-height:18px'}), '-');
this.contextMenu = new Ext.menu.Menu({ items: menuItemCfg });
}Note: the TextItem originally had an empty string, but this was observed to cause menu height issues with Extjs 3.3.3 in Firefox. Including a non-empty string ('Item') fixes this, and the string will never be observed as it is replaced with the node's text on show.

tdikarim
26 Jul 2011, 1:23 AM
Hi all,

I try to use this plugins, but I have no result displayed.
When I analyze on the server side, I receive no Callback parameter in the $_GET (php)

here is my code


var treePanelWest_ListeTable = new Ext.ux.tree.RemoteTreePanel({
id:'ListeTabletreePanelWest-id'
,autoScroll:true
,frame: false
,rootVisible:true
,renderTo: document.body
,useArrows: true
,containerScroll: true
,animate:true
,enableDD:false
,lines: true
,singleExpand:false
,layout: 'fit'

,root:{
nodeType:'async'
,id:'ListeTabletreePanelWest-source'
,text:'Root'
,expanded:true
,uiProvider:false
}

,loader: {
url:scriptUrl+'listeTable.php'
,preloadChildren:true
,requestMethod:'GET'
,baseParams:{
cmd:'getListeTable'
,treeTable:'tree'
,treeID:1
}
}
,onRender: function(ct, pos) {
Ext.tree.TreePanel.prototype.onRender.call(this, ct, pos);
}
});



I use Extjs 3.3.1

Thanks for help me

ericsmith66
19 Jan 2012, 9:43 AM
Hi,

We just discovered a bug in init method in RemoteTreePanel.js.
Line 11 reads
this.state = this.provider.get(this.stateName, {});
It needs to clone state, so it does not modify the state object of state provider. Bug comes out when using HttpStateProvider.

We fixed it by changing it to:
this.state = Ext.ux.util.clone(this.provider.get(this.stateName, {}));

Note: Ext.ux.util clone() helper function is required in order this to work.

Thanks