PDA

View Full Version : TreeNode Listener with PHP



mknopp
10 Mar 2008, 8:35 PM
I am working on setting up a context menu option for a tree.

mabello, was nice enough to provide me with code to achieve this using a specialized treeloader and listeners.

I tried to streamline this code by removing the modified treeloader and passing a listener attribute from PHP through JSON. However, it does not appear to be adding the listener attribute to the nodes.

Can a listener be passed into a standard treeloader through JSON? If so, what am I doing wrong? If not then is my only option the specialized treeloader?

Thank you for any help.

javascript


xt.onReady(function(){
Ext.BLANK_IMAGE_URL = '../ext/resources/images/default/s.gif';

// Right Click Code
var saveAction = new Ext.Action({
text: "Save",
handler: function(){
alert("Saving node of id->" + saveAction.selectedNode.attributes.id);
}
});

var onContextHide = function(scope){
if(this.ctxNode)
{
this.ctxNode.ui.removeClass('x-node-ctx');
this.ctxNode = null;
}
}

var userNodeInterceptor = {
click: function(node, eventObject){
var nodeId = node.attributes.id;
alert("Click on node of id->" + nodeId);
},

contextmenu : function(node, e){
if(!this.menu) // create context menu on first right click
{
this.menu = new Ext.menu.Menu({
id:'feeds-ctx',
items: [saveAction]
});
this.menu.on('hide', onContextHide, this);
}
if(this.ctxNode)
{
this.ctxNode.ui.removeClass('x-node-ctx');
this.ctxNode = null;
}
//if(node.isLeaf()){
this.ctxNode = node;
this.ctxNode.ui.addClass('x-node-ctx');
this.ctxNode.select();//Select the node
saveAction.selectedNode = node;
this.menu.showAt(e.getXY());
//}
}
};

// tabs for the center
var tabs = new Ext.TabPanel({
region: 'center',
margins:'3 3 3 0',
activeTab: 0,
defaults:{autoScroll:true},

items:[{
title: 'Contact',
html: 'Text in Tab 1'
},{
title: 'Employer',
html: 'Text in Tab 2',
closable: true
},{
title: 'Vendor',
html: 'Text in Tab 3',
closable: true
}]
});

var tree_loader = new Ext.tree.TreeLoader({
dataUrl: 'ext_test.php',
preloadChildren: true
});

// Panel for the west
var nav = new Ext.tree.TreePanel({
title: 'Navigation',
region: 'west',
split: true,
width: 250,
collapsible: true,
margins:'3 0 3 3',
cmargins:'3 3 3 3',
useArrows: true,
autoScroll: true,
animate: true,
enableDD: false,
containerScroll: true,
rootVisible: false,
loader: tree_loader
});

var root = new Ext.tree.AsyncTreeNode({
text: 'NComp Data',
draggable: false,
id: 'source'
});
nav.setRootNode(root);

var win = new Ext.Window({
title: 'Layout Window',
renderTo: 'content',
resizable: false,
x: 10,
y: 10,
constrain: true,
draggable: false,
closable:false ,
width:800,
height:350,
//border:false,
plain:true,
layout: 'border',

items: [nav, tabs]
});

win.show();
root.expand();
});


Here is a sample of the JSON being passed back from the PHP.


[{"text":"Ray Abad","id":"contacts\/11","cls":"file","leaf":"true","listeners":"userNodeInterceptor"},{"text":"Kibbles Bits","id":"contacts\/9","cls":"file","leaf":"true","listeners":"userNodeInterceptor"},{"text":"Johnny Bravo","id":"contacts\/18","cls":"file","leaf":"true","listeners":"userNodeInterceptor"},{"text":"Mike Bridge","id":"contacts\/13","cls":"file","leaf":"true","listeners":"userNodeInterceptor"},{"text":"Jane Brown","id":"contacts\/2","cls":"file","leaf":"true","listeners":"userNodeInterceptor"},{"text":"Jim Brown","id":"contacts\/19","cls":"file","leaf":"true","listeners":"userNodeInterceptor"}]

mabello
14 Mar 2008, 4:33 AM
Hi there,
looking for my name I've found this post.

The problem is that when the response return from the server, to trasform the json string in object the tree use internally somewhere Ext.decode(...), and in your case the value of the property listeners of your node object will be a string of course.

Anyway, if you do the following for each definitions of your nodes it will work:


{"text":"Ray Abad","id":"contacts\/11","cls":"file","leaf":"true","listeners": { "click": function(node, eventObject){ alert(node);}} }

Same thing for the contextmenu event...

I'm sure you can do also something better, but it's the first thing that came in my mind.

Otherwise, using the extension (I know you don't want to use it, but I'm sure you can do the same without extension) your task is really really simple:

Core part:


//this is your response string
var serverResponseString = '[{"text":"Ray Abad","id":"contacts\/11","cls":"file","leaf":"true","listeners": { "click": function(node, eventObject){ alert(node);}} },{"text":"Kibbles Bits","id":"contacts\/9","cls":"file","leaf":"true","listeners":"userNodeInterceptor"},{"text":"Johnny Bravo","id":"contacts\/18","cls":"file","leaf":"true","listeners":"userNodeInterceptor"},{"text":"Mike Bridge","id":"contacts\/13","cls":"file","leaf":"true","listeners":"userNodeInterceptor"},{"text":"Jane Brown","id":"contacts\/2","cls":"file","leaf":"true","listeners":"userNodeInterceptor"},{"text":"Jim Brown","id":"contacts\/19","cls":"file","leaf":"true","listeners":"userNodeInterceptor"}]';
//now there you go, the object
var serverResponseObject = Ext.decode(serverResponseString);
//used to add userInterceptor to all the nodes
function updateListeners(serverResponseObject, interceptor){
for(var i = 0; i < serverResponseObject.length; i++){
var node = serverResponseObject[i];
node.listeners = interceptor;
}
}

var treeNodeProvider = {
data: [],//Property in which are set the data to elaborate

getNodes: function() { //Here you process your data
return serverResponseObject;
},
setData: function(data) {//Called internally by Ext.tree.MyTreeLoader by the method updateTreeNodeProvider
this.data = data;
},
scope: this//Could be useful to use when you elaborates data to switch the context...not used in this example and it's not required
};


Very very simple:)

All the example:


<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
<title>Product View</title>

<link rel="stylesheet" type="text/css" href="../Styles/Page.css" />
<link rel="stylesheet" type="text/css" href="../resources2.0.2/css/ext-all.css" />
<link rel="stylesheet" type="text/css" href="../Styles/Action.css" />
<link rel="stylesheet" type="text/css" href="../Styles/FilterPanel.css" />
<link rel="stylesheet" type="text/css" href="../Styles/Tools.css" />
<script type="text/javascript">
//IE Bug Fix (caching of the images, don't flicker please!!!
try {
document.execCommand("BackgroundImageCache", false, true);
}
catch(err) {}
</script>


<script type="text/javascript" src="../scripts/Ext2.0.2/ext-base.js"></script>
<script type="text/javascript" src="../scripts/Ext2.0.2/ext-all-debug.js"></script>
<style type="text/css">
.ext-ie .x-form-item label.x-form-item-label{position:absolute;}
.ext-ie .x-form-label-top .x-form-item label.x-form-item-label{position:static;}
</style>
<%-- favicon --%>
<link rel="shortcut icon" href="~/Images/favicon.ico" />
</head>
<body>
<div id="tree-ct"></div>
</body>
<script type="text/javascript">

Ext.tree.MyTreeLoader = function(config){

Ext.apply(this, config);
Ext.tree.MyTreeLoader.superclass.constructor.call(this, config);

};

Ext.tree.MyTreeLoader = Ext.extend(Ext.tree.MyTreeLoader, Ext.tree.TreeLoader, {

treeNodeProvider: null,

loading: false,

load : function(node, callback){
if(this.clearOnLoad){
while(node.firstChild){
node.removeChild(node.firstChild);
}
}
if(this.doPreload(node)){ // preloaded json children
if(typeof callback == "function"){
callback();
}
}else if(this.treeNodeProvider){
this.requestData(node, callback);
}
},

requestData : function(node, callback){
if(this.fireEvent("beforeload", this, node, callback) !== false){
this.loading = true;
var nodesToAdd = this.treeNodeProvider.getNodes();
if(nodesToAdd)
this.processResponse(nodesToAdd, node, callback);
this.loading = false;
} else {
// if the load is cancelled, make sure we notify
// the node that we are done
if(typeof callback == "function"){
callback();
}
}
},

isLoading : function(){
return this.loading;
},

abort : function(){
},

processResponse : function(o, node, callback){
try {
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.fireEvent("loadexception", this, node, e);
if(typeof callback == "function"){
callback(this, node);
}
}
},

updateTreeNodeProvider: function(obj){
if(this.treeNodeProvider)
this.treeNodeProvider.setData(obj);
}
});

var flag = true;//To toggle the refresh



Ext.onReady(function(){

var userNodeInterceptor = {
click: function(node, eventObject){
var nodeId = node.attributes.id;
alert("Click on node of id->" + nodeId);
},

contextmenu : function(node, e){
if(!this.menu) // create context menu on first right click
{
this.menu = new Ext.menu.Menu({
id:'feeds-ctx',
items: [saveAction]
});
this.menu.on('hide', onContextHide, this);
}
if(this.ctxNode)
{
this.ctxNode.ui.removeClass('x-node-ctx');
this.ctxNode = null;
}
//if(node.isLeaf()){
this.ctxNode = node;
this.ctxNode.ui.addClass('x-node-ctx');
this.ctxNode.select();//Select the node
saveAction.selectedNode = node;
this.menu.showAt(e.getXY());
//}
}
};

var serverResponseString = '[{"text":"Ray Abad","id":"contacts\/11","cls":"file","leaf":"true","listeners": { "click": function(node, eventObject){ alert(node);}} },{"text":"Kibbles Bits","id":"contacts\/9","cls":"file","leaf":"true","listeners":"userNodeInterceptor"},{"text":"Johnny Bravo","id":"contacts\/18","cls":"file","leaf":"true","listeners":"userNodeInterceptor"},{"text":"Mike Bridge","id":"contacts\/13","cls":"file","leaf":"true","listeners":"userNodeInterceptor"},{"text":"Jane Brown","id":"contacts\/2","cls":"file","leaf":"true","listeners":"userNodeInterceptor"},{"text":"Jim Brown","id":"contacts\/19","cls":"file","leaf":"true","listeners":"userNodeInterceptor"}]';
var serverResponseObject = Ext.decode(serverResponseString);

function updateListeners(serverResponseObject, interceptor){
for(var i = 0; i < serverResponseObject.length; i++){
var node = serverResponseObject[i];
node.listeners = interceptor;
}
}

updateListeners(serverResponseObject, userNodeInterceptor);

var onContextHide = function(scope){
if(this.ctxNode)
{
this.ctxNode.ui.removeClass('x-node-ctx');
this.ctxNode = null;
}
}


// Right Click Code
var saveAction = new Ext.Action({
text: "Save",
handler: function(){
alert("Saving node of id->" + saveAction.selectedNode.attributes.id);
}
});

function getInterceptor(){
return userNodeInterceptor;
}

//Create your treeNodeProvider; it is an object that need to have this properties:
// data
var treeNodeProvider = {
data: [],//Property in which are set the data to elaborate

getNodes: function() { //Here you process your data
return serverResponseObject;
},
setData: function(data) {//Called internally by Ext.tree.MyTreeLoader by the method updateTreeNodeProvider
this.data = data;
},
scope: this//Could be useful to use when you elaborates data to switch the context...not used in this example and it's not required
};

var myTreeLoader = new Ext.tree.MyTreeLoader({
treeNodeProvider: treeNodeProvider
});



var basePanelCfg = {
title: 'TreePanel',
preloadChildren: true,
lines: false,
clearOnLoad: true,
rootVisible: false,
containerScroll: true,
frame: false,
collapsible: false,
animate: true,
loader: myTreeLoader
};

var treePanel = new Ext.tree.TreePanel(basePanelCfg);

var root = new Ext.tree.AsyncTreeNode({
text: 'Root',
draggable: false
});

treePanel.setRootNode(root);

// var innerPanel = {
// frame: true,
// title: "Details",
// items: [treePanel]
// };
treePanel.render('tree-ct');
treePanel.expandAll();

// new Ext.Viewport({
// layout:'fit',
// items:[treePanel]
// });
});
</script>
</html>



I know I'm fussy with this extension, but it makes really simple to test without a server side call and besides you can use your json response to load the tree like in this example

I hope this helps

mabello
14 Mar 2008, 2:26 PM
This is the solution that suite more you I think:


tree.on('click', function(node){
Ext.Msg.alert('Multiverse', node.id);
};

I hoe this helps

dee_psl
16 May 2008, 5:08 AM
Hey mabello,
Thanks a lot for your code in 'All Example'. I was also looking for the same feature in tree (Having menu on right click).
Being a newbie to extjs I just copy pasted your example, with just few changes it worked fine. Which in result saved all my initial efforts.

Thank you very much.

I will change the code as per my needs now. Will trouble you for sure if I need anything :)

And special thanks to mknopp also, for starting this thread.

Thanks
~Dee

mabello
16 May 2008, 7:03 AM
Dear dee_psl,
You are very welcome :), happy it helps you