Reload jstree data without ajax call

9,374 views
Skip to first unread message

Jean-Paul Ritz

unread,
Jan 18, 2014, 8:38:50 AM1/18/14
to jst...@googlegroups.com
Hi

For any reason I prefer loading jstree data with a json structure I provide. When I update the data structure I'd like to update the tree.
I googled a lot but didn't get the answer on how to do it properly. A lot of answer are about the ajax inside the tree but that is not I want to do
What is the best way to do that.
In practice what I do is:

Create a new jstree and load initial data from a json structure that work fine
update the data via my own process
reload the tree with data updated  this does not refresh the dom
for example I've added a tooltip on the node but it is not updated after the reload

Thanks in advance for the answer

Ivan Bozhanov

unread,
Jan 19, 2014, 3:20:27 PM1/19/14
to jst...@googlegroups.com
There is no way to reflect any changes without updating the DOM - why do you think updating the DOM is a bad thing (we are not talking about a refresh, but a DOM update right?).
To the question - simply use your own function which feeds data to jstree - http://www.jstree.com/docs/json - check the bottom of the page - "Using a function" ... So you simply maintain your structure and feed it to jstree as needed. And once you want jstree to reflect any changes to the structure, call $('#your-tree').jstree(true).refresh() - opened nodes and selection will be preserved.

Best regards,
Ivan

Jean-Paul Ritz

unread,
Jan 19, 2014, 4:45:08 PM1/19/14
to jst...@googlegroups.com
Hi Ivan

Thanks for your answer. I've tryied the solution you provided but when I do the refresh it only keep the root node the childs are lost. May be I am doing something wrong.


Here is a test code I just tried (tree is the jQuery node $("#myTree"))

$("#myTree").jstree({
            plugins: plugins,
            core: {
                data: function(obj, cb) {
                    cb.call(this, [{
                        text: 'Root 1',
                        children: ['child1']
                    }, 'Root 2']);
                },
                theme: {
                    "variant": "large",
                    dots: dots
                }
            }
        });
        $("#myTree").jstree(true).refresh();

Ivan Bozhanov

unread,
Jan 19, 2014, 6:02:49 PM1/19/14
to jst...@googlegroups.com
If you mean that the roots are closed - yes, that is so, because in your example you do not pass custom IDs. Make sure each node has a unique ID that you specify so that jstree can restore state.

Cheers,
Ivan

Jean-Paul Ritz

unread,
Jan 20, 2014, 1:11:52 AM1/20/14
to jst...@googlegroups.com
Hi Ivan

That is a good point I was not aware that I need to provide a unique ID to restore the state that works fine.
With the function described in the documentation mentioned by you I try it and  works for initializing the tree however I do not see how to feed the tree after the tree is initialized may be you have a full example. What I did for now as I keep an instance of the tree I just do the following and it works fine and restore the state as well.

jstree.settings.core.data = data;
jstree.refresh();

So no sure that it is a good the solution but it does the trick for now

I have another question concerning the contextual menu. It seems that the contextual menu is for all the tree my requirement is the have a different contextual menu on different node in the tree. If yes do you have an example to show.

And last question I can get the node selected but when I need also the click on the node for example if the tree is refreshed the selected node fire an event however I need to do an action only if I click again on the node is that possible .

Thanks a lot for your answer much apreciate





Le samedi 18 janvier 2014 14:38:50 UTC+1, Jean-Paul Ritz a écrit :

Ivan Bozhanov

unread,
Jan 20, 2014, 2:17:48 AM1/20/14
to jst...@googlegroups.com
Use refresh only - no need to set data manually (if it is a function).
As for the contextmenu - set items to a function (instead of an object - in that function you will get a first argument which you can use to determine which node was determined and return an object you want to use as the context menu:

items : function (obj) {
   // inspect obj
   return {
      "create" : { ....

Panos Meretis

unread,
Jan 29, 2014, 3:27:52 PM1/29/14
to jst...@googlegroups.com
I have almost similar issue, using the refresh function my tree is cleared up leaving only my parent node root.
How did you manage to provide a unique ID? 

Panos Meretis

unread,
Jan 30, 2014, 10:04:36 AM1/30/14
to jst...@googlegroups.com
I have kept a unique ID for each of my listnodes <li> (e.g. ID="1", ID="2"...)
and when I refresh the tree all the nodes are closed somehow.

Is there any reason that this happens? I mean it should refresh using the latest state, right?
I even tried the save_state(0 function...but nothing happened. Any ideas?

Gert

unread,
Jan 31, 2014, 2:42:35 PM1/31/14
to jst...@googlegroups.com
Hello,


Am Donnerstag, 30. Januar 2014 16:04:36 UTC+1 schrieb Panos Meretis:
I have kept a unique ID for each of my listnodes <li> (e.g. ID="1", ID="2"...)
and when I refresh the tree all the nodes are closed somehow.

 I do have the same (or similiar?) problem. The refresh is done bei Ajax load_node() calls. All my tree items do have unique IDs. When doing a refresh the treeview is reloaded, but the open folders from the second level on are all closed. The root folder and folder from the first hierarchy level are kept open fine.

Example:
  • root: open
    • Level1: open
      • Level2 open
        • Level 3, open
          • Level 4
      • Level 2, second item
    • Level1, second item
After doing the refresh it looks like this:
  • root: open
    • Level1: open
      • Level2 closed
      • Level 2, second item
    • Level1, second item
Is this a bug or am I missing something that is required for a correct refresh() call? As far as I understand the API documentation, jstree should do single calls to load_node() for each open folder automatically?

(Or is there a way to reload all displayed tree items in one Ajax call, e.g. by submitting the IDs of all open folders?)

Thank you,
Gert

Gert

unread,
Jan 31, 2014, 2:44:53 PM1/31/14
to jst...@googlegroups.com

Oh, btw: my jstree version is jstree-3.0.0-beta5-0

Ivan Bozhanov

unread,
Jan 31, 2014, 3:13:54 PM1/31/14
to jst...@googlegroups.com
Check to see if there is an error, and also - try using valid IDs - w3 specifies ID and NAME tokens clearly - just try adding a prefix to the node ID - like n1, n2, etc (so that they are valid IDs). Although most browsers would be fine with 1, 2, 3 - anyway - try it and let me know. Also - see if you get any error. If that does not help - I will have to see your config and data so that I can reproduce.

Ivan Bozhanov

unread,
Jan 31, 2014, 3:15:14 PM1/31/14
to jst...@googlegroups.com
Sorry, I have not way of reproducing your problem - all I can think of is - use valid IDs, make sure your IDs are really unique (not repeated throughout the document). If those are met - refresh should work properly. If it doesn't I will need to see your config and data.

Gert

unread,
Feb 5, 2014, 1:58:04 PM2/5/14
to jst...@googlegroups.com
Hi Ivan,

the IDs that I am using are mainly integers. Some of them containing a delimiter "T". So they look like: "123" or "123T44". Using a prefix "n" for all IDs did not change anything.

I have build a small test page and can reproduce the behaviour. If I open more than 3 levels of folders, a refresh just opens the folders up to level 3:

<html>
<head>
    <link rel="stylesheet" href="./dist/themes/default/style.css" />
    <script type="text/javascript" src="./dist/libs/jquery.js"></script>
    <script type="text/javascript" src="./dist/jstree.js"></script>

    <script type="text/javascript">
    jQuery(function() {
        jQuery('div#treeview').jstree({
            'core' : {
                "multiple" : false,
                "animation" : 100,
                'data' : {
                    'url' : '/cgi-bin/..../dispatcher.cgi',
                    'data' : function (node) {
                        return { 'id' : node.id };
                    }
                }
            }
        });
    })
    </script>

</head>
<body>
    <a href="#" onclick="jQuery('div#treeview').jstree().refresh()">refresh</a><br/><br/>
    <div id="treeview">
    </div>
</body>
</html>


On server side I am using this perl routine to return folders. The text of each entry is numbered like its id.
 
use JSON;

sub load_node_test {
    my ($self, %par) = @_;

    my  ($id, $debug) = 
    @par{'id','debug'};
    
    my @entries ;
    
    my $parent      = $id;
    my $entry_id    = $id * 1 + 1;
    
    my %entry = (
        id      => $entry_id,
        parent  => $parent,
        text    => $entry_id,
    );
    
    my $child_lr = [];
    if ( $id eq '#' ) {
        $child_lr = $self->load_node_test( id => $entry_id );
        
        $entry{state}{opened} = JSON::true;
    } else {
        $entry{children} = JSON::true;
    }

    push @entries, \%entry, @$child_lr;
    
    return \@entries;
}

The code runs in an ajax server context. The returned perl data is converted to JSON.

The response content-type is:
Content-Type: application/json;charset=utf-8

The first request with id="#" does return folder 1 and its subfolder 2:
[{"parent":"#","text":1,"id":1,"state":{"opened":true}},{"parent":1,"text":2,"children":true,"id":2}]

Opening folder 2 does return folder 3:
[{"parent":"2","text":3,"children":true,"id":3}]

Opening folder 3 does return folder 4:
[{"parent":"3","text":4,"children":true,"id":4}]

If I now click the refresh link, folder 1, 2 and 3 are loaded, but 3 is not opened. Folder 4 is missing.

If I open more than 4 folders, the refresh result will be the same: Only folders 1, 2 and 3 are displayed.

Here is the response of the refresh after opening folder 3:
Request 1:
[{"parent":"#","text":1,"id":1,"state":{"opened":true}},{"parent":1,"text":2,"children":true,"id":2}]
Request 2:
[{"parent":"2","text":3,"children":true,"id":3}]

I hope this helps to find the problem.

Regards,
Gert

Ivan Bozhanov

unread,
Feb 5, 2014, 4:45:06 PM2/5/14
to jst...@googlegroups.com
I think I got the problem - the alternative JSON format is only to be used when you return all data at once. Remove all references to "parent" and add the prefix (so response would be like this: [{"text":"1","id":"n1","state":{}}, ... ] and tell me if the issue persists.

Gert

unread,
Feb 6, 2014, 5:41:16 AM2/6/14
to jst...@googlegroups.com

Omitting the parent references does not change anything. Even if I turn off the loading of the second level on jsTree initialisation it does not work. Example:

Request 1 (Init of jsTree):
[{"text":1,"children":true,"id":1}]

Request 2 (Open folder 1):
[{"text":2,"children":true,"id":2}]

Request 3 (Open folder 2):
[{"text":3,"children":true,"id":3}]

Request 4 (Open folder 3):
[{"text":4,"children":true,"id":4}]


Refreshing the treeview:

Request 1:
[{"text":1,"children":true,"id":1}]

Request 2:
[{"text":2,"children":true,"id":2}]

=> Folder 3 (opened) and 4 (closed) are missing.

Greetings,
Gert

Gert

unread,
Feb 6, 2014, 5:46:02 AM2/6/14
to jst...@googlegroups.com

An addition: Doing the same test with the id-prefix "n" for all IDs leads to the same result. 

Ivan Bozhanov

unread,
Feb 6, 2014, 2:27:40 PM2/6/14
to jst...@googlegroups.com
You do have "return false" on the link onclick right? As now it will refresh the page :)
I added that and all seems fine ...

Gert

unread,
Feb 6, 2014, 2:35:38 PM2/6/14
to jst...@googlegroups.com

You do mean the refresh link in my example? Astonishing, but I did not need it. But it is better to include a "return false", so that the anchor-href does not trigger. It seems that your call of the refresh() method does not return true or false, but in my case it did!? 

Btw: I am testing with the latest firefox and chromium on Linux.

Does "all seems fine" mean that you cannot reproduce the behaviour?

Greetings,
Gert

Ivan Bozhanov

unread,
Feb 6, 2014, 8:10:16 PM2/6/14
to jst...@googlegroups.com
Yes, I cannot reproduce this neither in Firefox, nor Chrome, nor IE - I setup the example same as you did, but I used a function (not an AJAX call) - my guess is something messes up your AJAX call, but it is not jstree itself. The only thing left to do is for you to show me a live demo, I really cannot reproduce and I use this functionality all the time with no problem. Could you setup a demo somewhere?

Gert

unread,
Feb 7, 2014, 5:19:09 AM2/7/14
to jst...@googlegroups.com


Am Freitag, 7. Februar 2014 02:10:16 UTC+1 schrieb Ivan Bozhanov:
Could you setup a demo somewhere?

Please check the following link:

The server side script ist not exactly the same as in my development environment, so probably some headers are different. But the behaviour is the same.

Here is the server perl script:
#!/usr/bin/perl

use CGI;
use strict;
use JSON;

main: {
    my $cgi = CGI->new();
    my $id  = $cgi->param('id');

    print "Content-Type: application/json;charset=utf-8\n\n";

    my $entries_lr = load_node_test( id => $id );

    my $json = JSON->new();
    my $rc = $json->encode($entries_lr);

    print $rc;
}

sub load_node_test {
    my (%par) = @_;

    my  ($id, $debug) =
    @par{'id','debug'};

$id =~ s!^n!!;

    my $entry_id    = $id * 1 + 1;

$entry_id = 'n' . $entry_id;

    my %entry = (
        id      => $entry_id,
        text    => $entry_id,
        children => JSON::true,
    );

    return [\%entry];
}



Greetings,
Gert

Ivan Bozhanov

unread,
Feb 7, 2014, 8:23:16 AM2/7/14
to jst...@googlegroups.com
OK, I saw the error, but using the latest copy from github (not the one you have on your site) everything is fine. I believe I told you to get the latest copy didn't I? Sorry if that was a misunderstanding - I meant get the latest from github, not from jstree.com.

Best regards,
Ivan

Gert

unread,
Feb 7, 2014, 12:12:13 PM2/7/14
to jst...@googlegroups.com

Hi Ivan


Am Freitag, 7. Februar 2014 14:23:16 UTC+1 schrieb Ivan Bozhanov:
I believe I told you to get the latest copy didn't I?

Sorry, if you did, I must have missed this hint. With the master version refreshing does work fine! Great, thank you!

Wouldn't it be a good idea to refresh all tree items in just one ajax call? If jstree would submit the IDs of all open folders, the server could return all items in one go.

Greetings,
Gert

Ivan Bozhanov

unread,
Feb 9, 2014, 6:52:21 AM2/9/14
to jst...@googlegroups.com
You can use the alternative JSON syntax for that - it supports parent / child relations and its main purpose is to return the whole tree in one JSON.
You could of course use the other syntax too and return the whole tree, but it is a bit harder to build on the server side. I see what you mean and I know what I am suggesting is not the right answer, but it would over complicate things I believe.
There is a way to do that currently with some server side logic - it involves sending the state to the server each time you load a node, but it will be quite a lot of work.

Gert

unread,
Feb 10, 2014, 4:52:37 AM2/10/14
to jst...@googlegroups.com


Am Sonntag, 9. Februar 2014 12:52:21 UTC+1 schrieb Ivan Bozhanov: 
it would over complicate things I believe.

I have the idea to store all IDs of the open folders in a cookie (that is updated on each open/close_node event), that automatically is sent to the server on a load_node call. But does jstree handle the returned nodes automatically depending on the fact if only the loaded node itself and/or its children and/or its whole subtree is returned? So if jstree gets the whole tree at once on a refresh() call, will it understand that it does not need to do another ajax call for all opened folders?

Another idea is to call an own refresh method manually. I could traverse through the folders of jstree to find all open folders, so I can collect there IDs. Then I can call my own ajax routine to load the whole tree with the content of all opened folders. The only thing I need is a way to hand over the loaded JSON data to jstree via a javascript call. Is there such a method?

Greetings, 
Gert
 
Reply all
Reply to author
Forward
0 new messages