35

I'm trying to get a jsTree working with on demand loading of subnodes. My code is this:

jQuery('#introspection_tree').jstree({ 
        "json_data" : {
            "ajax" : {
                url : "http://localhost/introspection/introspection/product"
            }
    },
    "plugins" : [ "themes", "json_data", "ui" ]
    });

The json returned from the call is

[
  {
    "data": "Kit 1",
    "attr": {
      "id": "1"
    },
    "children": [
      [
        {
          "data": "Hardware",
          "attr": {
            "id": "2"
          },
          "children": [
            
          ]
        }
      ],
      [
        {
          "data": "Software",
          "attr": {
            "id": "3"
          },
          "children": [
            
          ]
        }
      ]
    ]
  }
  .....
]

Each element could have a lot of children, the tree is going to be big. Currently this is loading the whole tree at once, which could take some time. What do I have to do to implement on-demand-loading of child-nodes when they are opened by the user?

Thanks in advance.

Jean-Francois T.
  • 11,549
  • 7
  • 68
  • 107
Christian Waidner
  • 1,324
  • 1
  • 13
  • 22
  • How to use a function that returns a promise instead of url? I mean, use a dummy promise instead of ajax call – Mr_Perfect May 30 '19 at 15:38

5 Answers5

45

Irishka pointed me in the right direction, but does not fully resolve my problem. I fiddled around with her answer and came up with this. Using two different server functions is done only for clarity. The first one lists all products at top level, the second one lists all children of a given productid:

jQuery("#introspection_tree").jstree({
    "plugins" : ["themes", "json_data", "ui"],
    "json_data" : {
        "ajax" : {
            "type": 'GET',
            "url": function (node) {
                var nodeId = "";
                var url = ""
                if (node == -1)
                {
                    url = "http://localhost/introspection/introspection/product/";
                }
                else
                {
                    nodeId = node.attr('id');
                    url = "http://localhost/introspection/introspection/children/" + nodeId;
                }

                return url;
            },
            "success": function (new_data) {
                return new_data;
            }
        }
    }
});

The json data returned from the functions is like this (notice the state=closed in each node):

[
  {
    "data": "Kit 1",
    "attr": {
      "id": "1"
    },
    "state": "closed"
  },
  {
    "data": "KPCM 049",
    "attr": {
      "id": "4"
    },
    "state": "closed"
  },
  {
    "data": "Linux BSP",
    "attr": {
      "id": "8"
    },
    "state": "closed"
  }
]

No static data is needed, the tree is now fully dynamic on each level.

Jean-Francois T.
  • 11,549
  • 7
  • 68
  • 107
Christian Waidner
  • 1,324
  • 1
  • 13
  • 22
  • 6
    Thanks so much!! I've wasted way too much time trying to figure this out. Was not so clear from the documentation. – Carter Page Nov 29 '11 at 00:34
  • 18
    documentation sucks... at least for beginning with jstree – bbqchickenrobot Feb 16 '12 at 09:20
  • 3
    Thank you very much. The return data structure particularly helped me, since i was working under the false assumption that the returned JSON should be an object with children as an array, not the array itself. – arvidkahl Oct 12 '13 at 19:28
  • 2
    It works! I wasted hours on this problem. I missed the "state":"closed" Parameter. But also you need: "children":true on that parent item to get it worked! – Ruwen Jan 11 '17 at 11:02
  • 1
    @Christain `json_data` is not working for me. Is there any specific js file that I need to add before I use plugin? – prog1011 May 08 '19 at 14:04
  • AFAIK no - but the code is already 8 years old, so API may have changed. I'm not up-to-date anymore on this. – Christian Waidner May 10 '19 at 07:52
12

I guess it would be nice to display by default first level nodes and then the children will be loaded on demand. In that case the only thing you have to modify is to add "state" : "closed" to the nodes whose child nodes are going to be loaded on demand.

You might wish to send node's id in ajax call so you modify your code

"json_data": {
    //root elements to be displayed by default on the first load
    "data": [
        {
            "data": 'Kit 1',
            "attr": {
                "id": 'kit1'
            },
            "state": "closed"
        },
        {
            "data": 'Another node of level 1',
            "attr": {
                "id": 'kit1'
            },
            "state": "closed"
        }
    ],
    "ajax": {
        url: "http://localhost/introspection/introspection/product",
        data: function (n) {
            return {
                "nodeid": $.trim(n.attr('id'))
            }
        }
    }
}

From jsTree documentation

NOTE: If both data and ajax are set the initial tree is rendered from the data string. When opening a closed node (that has no loaded children) an AJAX request is made.

Arend
  • 3,741
  • 2
  • 27
  • 37
Radek
  • 13,813
  • 52
  • 161
  • 255
10

you need to set root elements as tree data on page load and then you will be able to retrieve their children with an ajax request

$("#introspection_tree").jstree({
    "plugins": ["themes", "json_data", "ui"],
    "json_data": {
        //root elements
        "data": [{"data": 'Kit 1', "attr": {"id": 'kit1'}} /*, ... */], //the 'id' can not start with a number 
        "ajax": {
            "type": 'POST',
            "data": {"action": 'getChildren'},
            "url": function (node) {
                var nodeId = node.attr('id'); //id="kit1"

                return 'yuorPathTo/GetChildrenScript/' + nodeId;
            },
            "success": function (new_data) {
                //where new_data = node children 
                //e.g.: [{'data':'Hardware','attr':{'id':'child2'}}, {'data':'Software','attr':{'id':'child3'}}]
                return new_data;
            }
        }
    }
});

See my answer to a similar question here (the old part) for more details

Community
  • 1
  • 1
Irishka
  • 1,136
  • 6
  • 12
  • What is the reason for id not starting with a number? – Christian Waidner Nov 11 '11 at 12:50
  • 2
    Syntax Attribute Values Value Description id Specifies a unique id for an element. Naming rules: Must begin with a letter A-Z or a-z Can be followed by: letters (A-Za-z), digits (0-9), hyphens ("-"), and underscores ("_") In HTML, all values are case-insensitive see here [http://www.w3schools.com/tags/att_standard_id.asp] – Irishka Nov 11 '11 at 12:53
3

I spended hours on this problem. Finally i got it that way:

$("#resourceTree").jstree({
    "types": {
      "default": {
        "icon": "fa fa-folder-open treeFolderIcon",
      }
    },
    "plugins": ["json_data", "types", "wholerow", "search"],
    "core": {
      "multiple": false,
      "data": {
        "url" : function(node){
          var url = "rootTree.json";
          if(node.id === "specialChildSubTree")
            url = "specialChildSubTree.json";
          return url;
        },
        "data" : function(node){
          return {"id" : node.id};
        }
      }
    },
  });

rootTree.json:

[
  {
    "text": "Opened root folder",
    "state": {
      "opened": true
    },
    "children": [
      {
        "id" : "specialChildSubTree",
        "state": "closed",
        "children":true
      }
    ]
  }
]

specialChildSubTree.json:

[
  "Child 1",
  {
    "text": "Child 2",
    "children": [
      "One more"
    ]
  }
]

So i mark the node that become the parent of the ajax loaded subtree with an id, i watch for in the core configuration.

NOTE: That node must have the "state" : "closed" parameter and it must have the parameter "children" : true.

I am using jsTree.js in version 3.3.3

Ruwen
  • 3,008
  • 1
  • 19
  • 16
2

Above solution is all fine. Here I am also providing similar working solution and very simple for lazy loading of nodes using ajax call vakata. When your API works like

https://www.jstree.com/fiddle/?lazy

and for getting any child nodes

https://www.jstree.com/fiddle/?lazy&id=2

for explanation and for complete solution you can have a look at https://everyething.com/Example-of-jsTree-with-lazy-loading-and-AJAX-call

<script type="text/javascript">
        $(function () {
            $('#SimpleJSTree').jstree({
                'core' : {
                    'data' : {
                        'url' : "https://www.jstree.com/fiddle/?lazy", 
                        'data' : function (node) { 
                            return { 'id' : node.id }; 
                        } 
                    } 
                } 
            });
        });
    </script>
Asif Nowaj
  • 346
  • 2
  • 9