5

Problem:

According to the author, jsTree Documentation:

When opening a closed node (that has no loaded children) an AJAX request is made.

How do I configure jsTree to get rid of these AJAX data requests made for each empty/childless node? I want my empty nodes remain empty (or childless)!


Given (simplified):

JSON data container (data.json)

{
    "data" : "Root node with no children",
    "children" : []
}

jsTree configuration

{
    "json_data" : {
        "ajax" : {
            "url"        : "data.json",
            "type"       : "GET",
            "dataType"   : "json",
            "dataFilter" : function (data, type) {
                //some filtering function
            }
        }
    },
    "plugin" : ["json_data"]
}

Community
  • 1
  • 1
John Doe
  • 4,574
  • 2
  • 26
  • 30

5 Answers5

11

Mark the state of the leaf node as "leaf". That should fix it.

Sree Kollu
  • 126
  • 1
  • 3
1

I have had this problem setting the attribute state="closed" on childless nodes for XML trees. Removing the state attribute solves the issue.

Oscar
  • 11
  • 1
0

I've been struggling with this problem too. I got the main idea from jsTree - loading subnodes via ajax on demand

The basic problem is that when we click a child node that is not set to leaf, a new AJAX request is generated with the URL we set in the tree configuration. The trick seen in the above link is to provide a function instead of a static URL string. My jstree is used to display a directory structure on the server, so I can arrange to dynamically add to the URL for sub-directories. If you assign a function to the url property of the ajax property in your jstree configuration, the function receives the node you clicked as an argument. My nodes display the names of directories or files so I can use the text() function to get the raw directory name. There seems to be some space in front of the name returned in this way, so I used a String trim() function and then encodeURIComponent to give me something I can use in a URL.

If -1 is passed to the url function, then you're at the root and you can safely use your base URL. Now, this only works for the first level of the hierarchy. I've got a bit more work to do, adding the full path to the metadata of the node or something like that, but this idea might put you on the right track. It looks as if it's not exactly a bug but by design. You have to make sure a request triggered by a subnode sends a suitable URL to the server.

Here's the url property I've assigned to the ajax object in my jstree configuration:

"url": function (node) {
    var subDirectory = "",
    url = "";
    if (node === -1)
    {
        url = "/tree_service/tree/format/json?path=exercises";
    }
    else
    {
        subDirectory = encodeURIComponent(node.text().trim());
        url = "/tree_service/tree/format/json?path=exercises/" + subDirectory;
    }
    return url;
}

My plan is to build the URL cumulatively by polling the node for its full path, then adding the node's name as above to create the final URL. Pseudo code:

//haven't figured out how to add the path to the node and then retrieve it
path = node.metadata.path;
path = encodeURIComponent(path);
subDirectory = encodeURIComponent(node.text().trim());
url = path + "/" + subDirectory;

UPDATE See my answer here how to get the metadata of jsTree. about getting the metadata from the node using node.data().path

Community
  • 1
  • 1
DavidHyogo
  • 2,838
  • 4
  • 31
  • 48
0

I had a similar problem a couple of weeks ago. I had a function call in the "url" field, which ultimately led to java code that made a JSON string based on a SQL query. So when I clicked on a childless closed node, the function was called again, resulting in an endless tree.

the way I solved this was:

"json_data" : {
        "ajax" : {
            "url" : "getAreaTree?treeType=Areas&ownerPhone=<%=webSessionObject.getUserPhoneNum()%>",
            "data" : function (n) {
                    return { id : n.attr ? n.attr("id") : 0 };
                }
        }
    },

The result of the function defined in "data" will be added as a parameter to the "url" function. Then I can check whether the parameter was 0 (initial load) or 1 (the id of my root) or something else.

If this doesn't work for you, maybe you could try something like this:

.bind("before.jstree",function(event,data){
    if(data.func === "create"){
                  var foo = true;
        data.inst._get_node(null, true).each(function () {

            if(this.id!=rootId && this.id!=0){
                foo = false;    
        })
        if(!foo){
            event.stopImmediatePropagation();
            return false;
        }
    }       
})

I'm not exactly sure this works though. "before.jstree" fires before all events. I'm checking whether the function about to fire is "create", and if it is I check the id of the selected node. If it's something else than my root's id or 0 (initial load) I stop the create function.

I use a similar structure for a different situation, so something like this should work. It could be that the "create" event is not what you should be binding to though. You can change it to

.bind("before.jstree",function(event,data){
            console.log(data.func)
    if(data.func === "create"){

To see which functions are called.

T.Kaukoranta
  • 415
  • 10
  • 25
  • In my initial answer I had "loaded" as the binded event. I edited it to "create", but don't be confused if somewhere in my post I still talk about "loaded" - it's just lazy editing. – T.Kaukoranta May 24 '11 at 08:03
  • Your first suggestion with specifying a callback function that adds some data to the GET-request does not work for me: 'cause I ask a server for a file (*.json) directly without any request processing and adding any "arguments" to the URL is pointless in my case... – John Doe May 24 '11 at 14:10
  • I thought so, but I posted it since I thought it could help somehow. Did you try the "before" trick? Honestly, this feature of jstree is really annoying, and I'm not aware of any easy way around it. – T.Kaukoranta May 25 '11 at 06:08
0

Just skip the children attribute. Obviously your node has no children, but you specify the attribute? Simply skip it, the node will be rendered as a leaf node and no further requests will be made.

  • dear Ivan! the resulting object that is prepared to be _JSON.stringified_ and sent to the jsTree plugin has all the empty children nodes **deleted** during preparation. but still those childless nodes are displayed as ones having children. and once I click an arrow to open that node an AJAX request is made -> I end up having infinite tree... – John Doe May 24 '11 at 14:05
  • I have also tried adding the `"load_open": true` to the configuration of the jsTree, but the behaviour was as follows: the supposed childless nodes are displayed as ones with children, and trying to open a node for the 1st makes blocks any server requests. **but** when opening that childless node the 2nd time a request is made. – John Doe May 24 '11 at 14:18
  • I am currently using the **1.0-rc1** version (rev. 191) of jsTree. Might that cause troubles I am having? – John Doe May 25 '11 at 10:30