Search code examples
jqueryajaxjstreejquery-deferred

JsTree open nodes programmatically, data source is json/ajax


I've got a jsTree, launched with following code:

$(function () {
  var grid = $('#group-tree');
  grid
      .jstree({
          core: {
              data: {
                  url: '<url to json source>',
                  data: function (node) {
                      return {'id': node.id};
                  }
              },
              'multiple': false,
              'animation': false
          }
      });
});

Source of data is json, getted via ajax. I have an array of ids, which I need to expand when tree is showed. For example:

0
|_1
|_2
  |_2.1
  |_2.2
    |_2.2.1
      |_2.2.1.1

My list is ['0', '2','2.2', '2.2.1'].

I've tried the following code (added after var grid = $('#group-tree');):

grid.on('ready.jstree', function (e, data) {
    // ids of nodes I need to expand
    var nodeValues = ['0', '2','2.2', '2.2.1'];
    nodeValues.forEach(function (item) {
        $('#group-tree').jstree(true).open_node(item);
    });
});

Node with id=0 opens succesfully, but id=2 not opened, because it's still not loaded when I open id=0 node.

How to successively call open_node to open all nodes in my case?

P.S. I've found simular answer/solution pair here, but I don't understand the code, solution didn't helped.


Solution

  • My solution is the code below, explanation is in comments:

    $(function () {
        // tree container
        var grid = $('#group-tree');
        // queue of callbacks to be executed on node load
        var node_callbacks_queue = [];
        // list of ids of nodes to be expanded on tree first load
        var node_values = ['0', '2', '2.2', '2.2.1'];
        /**
         * @see https://github.com/naugtur/insertionQuery
         */
        insertionQ('#group-tree .jstree-node').every(function (element) {
            // this callback executes when new node appeared in the DOM
    
            // add function, which handles new added node, to the queue
            node_callbacks_queue.push(function () {
                // id of new node
                var item_id = parseInt($(element).attr('id'));
                // index of new node it the list of nodes I need to open
                var item_index = node_values.indexOf(item_id);
                // node shouldn't be opened on start, exit
                if (item_index == -1) {
                    return;
                }
    
                // open node
                $('#group-tree').jstree(true).open_node(
                    item_id, 
                    function() { 
                        // remove id of node from the list of nodes I need to expand
                        node_values.splice(item_index, 1);
                    },
                    false
                );            
            });
        });
        var open_nodes_interval = setInterval(
            // this one executes 10 times in second
            function () {
                // execute all callbacks in queue
                node_callbacks_queue.forEach(function (func) {
                    func();
                });
                // until all nodes, I need to expand, is handled
                if (!node_values.length) {
                    clearInterval(open_nodes_interval);
                }
            },
            100
        );
        grid
            .jstree({
                core: {
                    data: {
                        url: '<url to json source>',
                        data: function (node) {
                            return {'id': node.id};
                        }
                    },
                    'multiple': false,
                    'animation': false
                }
            });
    });