PDA

View Full Version : How to save state of Tree. Was: Moving nodes



prhanna
20 Sep 2007, 10:01 AM
Hello All,
I have a tree loaded statically using a json string to define the structure of the tree. I managed to setup the tree with drag&drop enabled.

It works as desired, however, now I would like to store changes to the tree structure caused by the user dragging and dropping a node to a different location in the same tree. I can't for some reason, find any documentation to help do that. Any help is greatly appreciated. Examples would be perfect!

I would like to have the tree update a database with the new node's parent and position under the parent whenever it is dropped (using AJAX i presume).

Thanks in advance!

Animal
21 Sep 2007, 12:27 AM
Use the TreeSerializer class provided here:

http://extjs.com/forum/showthread.php?p=25261#post25261

Animal
21 Sep 2007, 12:30 AM
Please post in the appropriate forum, and give your thread a meaningful title.

You are asking for help saving the state of a tree!

goodieboy
30 Nov 2007, 11:33 AM
Not sure if this is the right place to put it... but I fixed a couple of syntax errors in the Ext.tree.TreeSerializer and it actually works great for what I'm trying to do :)



// jquery
$('input#update').click(function(){
s = new Ext.tree.JsonTreeSerializer(tree, {
nodeFilter:function(node){ return 'true' }
});
$.post('/content_nodes/reset', {
data:s.toString()
}, function(response){
alert(response);
})
});


If there is a more current version somewhere, could someone let me know?



/**
* @class Ext.tree.TreeSerializer
* A base class for implementations which provide serialization of an
* {@link Ext.tree.TreePanel}.
* <p>
* Implementations must provide a toString method which returns the serialized
* representation of the tree.
*
* @constructor
* @param {TreePanel} tree
* @param {Object} config
*/
Ext.tree.TreeSerializer = function(tree, config){
if (typeof this.toString !== 'function') {
throw 'Ext.tree.TreeSerializer implementation does not implement toString()';
}
this.tree = tree;
if (this.attributeFilter) {
this.attributeFilter = this.attributeFilter.createInterceptor(this.defaultAttributeFilter);
} else {
this.attributeFilter = this.defaultAttributeFilter;
}
if (this.nodeFilter) {
this.nodeFilter = this.nodeFilter.createInterceptor(this.defaultNodeFilter);
} else {
this.nodeFilter = this.defaultFilter;
}
Ext.apply(this, config);
};

Ext.tree.TreeSerializer.prototype = {

/*
* @cfg nodeFilter {Function} (optional) A function, which when passed the node, returns true or false to include
* or exclude the node.
*/
/*
* @cfg attributeFilter {Function} (optional) A function, which when passed an attribute name, and an attribute value,
* returns true or false to include or exclude the attribute.
*/
/*
* @cfg attributeMap {Array} (Optional) An associative array mapping Node attribute names to XML attribute names.
*/

/* @private
* Array of node attributes to ignore.
*/
standardAttributes: ["expanded", "allowDrag", "allowDrop", "disabled", "icon",
"cls", "iconCls", "href", "hrefTarget", "qtip", "singleClickExpand", "uiProvider",

// EXTRAS
"loader", "draggable", "leaf"],


/** @private
* Default attribute filter.
* Rejects functions and standard attributes.
*/
defaultAttributeFilter: function(attName, attValue) {
return (typeof attValue != 'function') &&
(this.standardAttributes.indexOf(attName) == -1);
},

/** @private
* Default node filter.
* Accepts all nodes.
*/
defaultNodeFilter: function(node) {
return true;
}
};

/**
* @class Ext.tree.XmlTreeSerializer
* An implementation of Ext.tree.TreeSerializer which serializes an
* {@link Ext.tree.TreePanel} to an XML string.
*/
Ext.tree.XmlTreeSerializer = function(tree, config){
Ext.tree.XmlTreeSerializer.superclass.constructor.apply(this, arguments);
};

Ext.extend(Ext.tree.XmlTreeSerializer, Ext.tree.TreeSerializer, {
/**
* Returns a string of XML that represents the tree
* @return {String}
*/
toString: function(nodeFilter, attributeFilter){
return '\u003C?xml version="1.0"?>\u003Ctree>' + this.nodeToString(this.tree.getRootNode()) + '\u003C/tree>';
},

/**
* Returns a string of XML that represents the node
* @param {Object} node The node to serialize
* @return {String}
*/
nodeToString: function(node){
if (!this.nodeFilter(node)) {
return '';
}
var result = '\u003Cnode';
if (this.attributeFilter("id", node.id)) {
result += ' id="' + node.id + '"';
}

// Add all user-added attributes unless rejected by the attributeFilter.
for(var key in node.attributes) {
if (this.attributeFilter(key, node.attributes[key])) {
result += ' ' + (this.attributeMap ? (this.attributeMap[key] || key) : key) + '="' + node.attributes[key] + '"';
}
}

// Add child nodes if any
var children = node.childNodes;
var clen = children.length;
if(clen == 0){
result += '/>';
}else{
result += '>';
for(var i = 0; i < clen; i++){
result += this.nodeToString(children[i]);
}
result += '\u003C/node>';
}
return result;
}

});

/**
* @class Ext.tree.JsonTreeSerializer
* An implementation of Ext.tree.TreeSerializer which serializes an
* {@link Ext.tree.TreePanel} to a Json string.
*/
Ext.tree.JsonTreeSerializer = function(tree, config){
Ext.tree.JsonTreeSerializer.superclass.constructor.apply(this, arguments);
};

Ext.extend(Ext.tree.JsonTreeSerializer, Ext.tree.TreeSerializer, {

/**
* Returns a string of Json that represents the tree
* @return {String}
*/
toString: function(){
return this.nodeToString(this.tree.getRootNode());
},

/**
* Returns a string of Json that represents the node
* @param {Object} node The node to serialize
*/
nodeToString: function(node){
// Exclude nodes based on caller-supplied filtering function
if (!this.nodeFilter(node)) {
return '';
}
var c = false, result = "{";
if (this.attributeFilter("id", node.id)) {
result += '"id":"' + node.id + '"';
c = true;
}

// Add all user-added attributes unless rejected by the attributeFilter.
for(var key in node.attributes) {
if (this.attributeFilter(key, node.attributes[key])) {
if (c) result += ',';
result += '"' + (this.attributeMap ? (this.attributeMap[key] || key) : key) + '":"' + node.attributes[key] + '"';
c = true;
}
}

// Add child nodes if any
var children = node.childNodes;
var clen = children.length;
if(clen != 0){
if (c) result += ',';
result += '"children":['
for(var i = 0; i < clen; i++){
if (i > 0) result += ',';
result += this.nodeToString(children[i]);
}
result += ']';
}
return result + "}";
}
});

Allan
14 Mar 2008, 4:16 AM
Hi,

this worked for me:



// Code to handle re-parenting
//
function updateTreeElementParentSuccess() {

}

function updateTreeElementParentFailure() {
alert('Error: Failed to move to new section in database');
}

function handleMoveNode( tree, node, oldParent, newParent, index) {
//alert("node being dropped");
if(node.leaf == false) {
url = '/testplans/'+testplanId+'/testplan_sections/'+node.attributes.id+'/move_to_section';
}
else {
url = '/testplans/'+testplanId+'/testplan_sections/'+node.parentNode.attributes.id+'/testplan_expectations/'+node.attributes.id+'/move_to_section';
}
params = {'section_id':newParent.attributes.id};
Ext.Ajax.request({
url: url,
method:'PUT',
success: updateTreeElementParentSuccess,
failure: updateTreeElementParentFailure,
params: params
});
}

testPlanTree.addListener('movenode', handleMoveNode);
testPlanTree.addListener('beforemovenode', function(t,node,oldParent,newParent,i) {
if( oldParent.id == newParent.id ) {
alert("Re-ordering not supported");
return false;
}
});


Note that my server app. is Ruby on Rails and those urls are nested resources, probably no longer considered good design by the RoR community...

Hope this helps anyone searching for tree node update saving.

Allan

barboul
23 Apr 2008, 4:00 AM
Hello,

I think I have the same problem... I would like to know what the user change in the tree...

I am new with JSON (I started yesterday :D). But I manage already to wrote the PHP script to show the tree according to the data from our database:

include('../../../../pages/mysql_connection.php');

//WRITE THE JSON SCRIPT FROM THE DATABASE
$rq_struct_code1="SELECT * FROM structure WHERE world_region_id IS NULL AND level1_id!=0 AND level1_id!=4";
$res_struct1=mysql_query($rq_struct_code1) or die(mysql_error());

$retour3 = mysql_query("SELECT COUNT(*) AS nbre3 FROM structure WHERE world_region_id IS NULL AND level1_id!=0 AND level1_id!=4");
$donnees3 = mysql_fetch_array($retour3);
$nbre3=$donnees3['nbre3'];
$k=0;

//1st level from the database
echo"[";
while ($structure_res1 = mysql_fetch_array($res_struct1)){
$k++;
$structure_id1=$structure_res1['structure_id'];
$structure_code1=$structure_res1['structure_code'];
$level1_id1=$structure_res1['level1_id'];
echo"{id:$structure_id1 , text: '$structure_code1', children: [";

//take the 2nd level from the database
$rq_struct_code2="SELECT * FROM structure WHERE level1_id='$level1_id1' AND level3_id=0";
$res_struct2=mysql_query($rq_struct_code2) or die(mysql_error());

$retour2 = mysql_query("SELECT COUNT(*) AS nbre2 FROM structure WHERE level1_id='$level1_id1' AND level3_id=0");
$donnees2 = mysql_fetch_array($retour2);
$nbre2=$donnees2['nbre2'];
$j=0;
while ($structure_res2 = mysql_fetch_array($res_struct2)){
$structure_id2=$structure_res2['structure_id'];
$structure_name2=$structure_res2['structure_code'];
$level2_id2=$structure_res2['level2_id'];
$j++;
if($structure_id2==10){
$structure_name2=$structure_res2['structure_name'];
echo"{id:$structure_id2 , text: '$structure_name2', leaf: true},";
}else{
echo"{id:$structure_id2 , text: '$structure_name2', children: [";

//take the 3rd level from the database
$rq_struct_code3="SELECT * FROM structure WHERE level2_id='$level2_id2' AND level3_id=1";
$res_struct3=mysql_query($rq_struct_code3) or die(mysql_error());

$retour = mysql_query("SELECT COUNT(*) AS nbre FROM structure WHERE level2_id='$level2_id2' AND level3_id=1");
$donnees = mysql_fetch_array($retour);
$i=0;
$nbre=$donnees['nbre'];
while ($structure_res3 = mysql_fetch_array($res_struct3)){
$structure_id3=$structure_res3['structure_id'];
$structure_name3=$structure_res3['structure_name'];
$i++;
if($i==$nbre){
echo"{id:$structure_id3 , text: '$structure_name3', leaf: true}";
}else{
echo"{id:$structure_id3 , text: '$structure_name3', leaf: true},";
}
}
if($j==$nbre2){echo"]}";}else{echo"]},";}
}
} if($k==$nbre3){echo"]}";}else{echo"]},";}

}
//end of the json script
echo"]";The PHP script is working fine and display correctly the nodes and so on. Now I am looking for a way to get the JSON string after the user change all the tree and modify the database according to the users' changes.
Can you help me with that and explain me in a simple way? It will be great! ;) Thanks a lot!

PS: I had a look to the forum and some solutions have been offered: http://extjs.com/forum/showthread.php?t=2516&page=4
http://extjs.com/forum/showthread.php?p=131816

I would have a closed look to that too!