PDA

View Full Version : [UNKNOWN][3.0.0/2.2.1] Issue with dynamically created TreeNodes



Paul Coldrey
20 Aug 2009, 9:12 PM
In the attached file bug.zip is the cut down source of an app I have been working on. Basically I am looking to be able to dynamically build a tree where leaves can become branches simply by having a child added. To help with the workflow I add the child node (by added to the database and then reloading the containing node) and then set it to be immediately edited so I can put in a sensible description. The initial tree is shown in screen.png. My issue is that if I add to any of the first level nodes (eg sub 1.1 or sub 1.2) then everything works fine. If I add to any nodes deeper in the tree (eg sub 1.1.1) then it barfs with:

Error: targetNode is undefined
Source File: http://gus/extjs/ext-all-debug.js
Line: 24866

If I the click on the node that should have had a child added then I get:

Error: [Exception... "Component returned failure code: 0x80004003 (NS_ERROR_INVALID_POINTER) [nsIDOMHTMLUListElement.appendChild]" nsresult: "0x80004003 (NS_ERROR_INVALID_POINTER)" location: "JS frame :: http://gus/extjs/ext-all-debug.js :: anonymous :: line 24866" data: no]
Source File: http://gus/extjs/ext-all-debug.js
Line: 24866

When I added code to allow me to force a reload on the node then my newly created nodes are there and work correctly (until I try to add a child to them, of course)

I have been looking to blame myself for this but after a lot of soul-searching I decided it looked very like a bug. It can be repeated with 2.2.1 and 3.0.0.

The file bug.sql contains the SQL script to create the MySQL database used in the example code.

For those who don't like to look into ZIP files, the crux of my code is:


function selectChildNode(node) {
var selModel = tree.getSelectionModel();
node.firstChild.select();
var newnode = selModel.getSelectedNode();
treeeditor.editNode=newnode;
treeeditor.startEdit(newnode.ui.textNode, newnode.text);
}

function onAddChild(item){
var node = item.parentMenu.node;
if (node instanceof Ext.tree.AsyncTreeNode) {
// if this was not a leaf then we just need to add another child
var newnode = node.appendChild(new Ext.tree.TreeNode({text: 'hello', leaf: true, parentid: node.attributes.dbid }));
newnode.select();
treeeditor.editNode=newnode
treeeditor.startEdit(newnode.ui.textNode, newnode.text);
} else {
// leaf node - so we need to turn it into a branch and then do the add
var parent = node.parentNode;
parent.select();
var replaceNode = new Ext.tree.AsyncTreeNode({dbid: node.attributes.dbid, text: node.attributes.text, leaf: false});
parent.replaceChild(replaceNode, node);
node = replaceNode;
Ext.Ajax.request({
url: '/ajax/tree/addnode.php',
success: function(result, request) {
node.expand(false, true, selectChildNode);
},
failure: function() {
Ext.MessageBox.alert('Message', 'Fail');
},
waitMsg:'Waiting...',
params: { dbid: node.attributes.dbid, text: '[description]' }
});
}
}

Paul Coldrey
20 Aug 2009, 10:16 PM
As is so often the case,.. one gets to the point of frustration, reports an issue, drinks a beer and with fresh perspective neatens up the code and so works around the problem. Having said that I still suspect the problem I reported may be a bug.

For any who follow, I resolved this issue by overloading the createNode function for the TreeLoader so that all nodes are AsyncTreeNodes (I figured my on-the-fly replacement of nodes was probably the root of the problem). Having done this I have half as much code and it works. The salient functions are:


function onTreeEditComplete(el, newText, oldText)
{
Ext.Ajax.request({
url: '/ajax/tree/updatetext.php',
success: function(result, request) {
},
failure: function() {
Ext.MessageBox.alert('Message', 'Fail');
},
waitMsg:'Waiting...',
params: { dbid: el.editNode.attributes.dbid, text: newText }
});
}

function selectChildNode(node) {
var selModel = tree.getSelectionModel();
node.firstChild.select();
var newnode = selModel.getSelectedNode();
treeeditor.editNode=newnode;
treeeditor.startEdit(newnode.ui.textNode, newnode.text);
}

function onAddChild(item){
var node = item.parentMenu.node;
node.attributes.leaf = false;
Ext.Ajax.request({
url: '/ajax/tree/addnode.php',
success: function(result, request) {
node.expand(false, true, selectChildNode);
},
failure: function() {
Ext.MessageBox.alert('Message', 'Fail');
},
waitMsg:'Waiting...',
params: { dbid: node.attributes.dbid, text: '[description]' }
});
}

function treeLoaderCreateNode(attr) {
var node;
if (attr.expandable) {
node = new Ext.tree.AsyncTreeNode(attr);
} else {
node = new Ext.tree.AsyncTreeNode(attr);
}
return node;
};