I am trying to dynamically load the nodes of a jtree when they are expanded. The little documentation I found is at the end of this page.
I found some solutions that cre
I'll give you that the documentation/examples is pretty rough. I'll also add that the source of your confusion comes from a major upgrade - the old version doesn't have much in common with the new version and unfortunately most examples were written against that old version.
The good news is that lazy loading is supported out of the box, it just isn't that obvious. The key is that it does call your data:
config as each node is expanded. But in order for it to work, the URL function must return a different URL for the given node. In the code below, note the condition to return one URL if the node is root (#
), and another if it is not.
$('#TreeDiv')
.jstree({
core: {
data: {
url: function (node) {
return node.id === '#' ? '/UserAccount/AccountGroupPermissions'
: '/UserAccount/AccountPermissions/' + node.id;
},
type: 'POST'
}
},
plugins : ["checkbox"]
});
To make a lazy loading, you need a backend that returns a JSON object with tree nodes that has children property field. Children property must contain children elements or boolean true (array or boolean). With a strongly typed language on your backend it is going to be ugly, so its best to deal with it on frontend. Example of AJAX success callback:
$('#tree').jstree({
'core' : {
'data' : {
'url' : function(node) {
return '/doc/test2';
},
'data' : function(node) {
return {
'part' : node.id === '#' ? pn : node.id
};
},
'success' : function(nodes) {
var validateChildrenArray = function(node) {
if (!node.children || node.children.length === 0) {
node.children = true;
}
else {
for (var i = 0; i < node.children.length; i++) {
validateChildrenArray(node.children[i]);
}
}
};
for (var i = 0; i < nodes.length; i++) {
validateChildrenArray(nodes[i]);
}
}
}
}
});
By doing this, you are going to be able to lazy load your tree.
Extending Nathans answer with a (very minimalistic) example: the Demo tree with lazy loading.
JS:
$('#the_tree').jstree({
'core' : {
'data' : {
'url' : "tree/ajax.php",
'data' : function (node) {
return { 'id' : node.id };
}
}
},
});
PHP:
header('Content-Type: application/json');
if ( $_GET["id"] === "#" ) {
$data = array(
array( "id" => "ajson1", "parent" => "#", "text" => "Simple root node" ),
array( "id" => "ajson2", "parent" => "#", "text" => "Root node 2", "children" => true ),
);
}
else if ( $_GET["id"] === "ajson2" ) {
$data = array(
array( "id" => "ajson3", "parent" => "ajson2", "text" => "Child 1" ),
array( "id" => "ajson4", "parent" => "ajson2", "text" => "Child 2" )
);
}
echo json_encode( $data);
only Nodes that have "children" : true
, will generate a request for children when opened, other nodes are treated as leaves.
I made my customized lazy loading by combining "select_node.jstree" event and "create_node" method. On selecting every node, event handler checks if there are children and adds response of server to selected node, node by node. My server response was not similar or requirements of jstree and this strategy saved me a lot of time and effort. Hope it helps somebody.
"When using AJAX set children to boolean true and jsTree will render the node as closed and make an additional request for that node when the user opens it.", this is from jstree document and it could achieve your requirement.