Search code examples
jqueryform-submitjqtree

jqTree getState and setState -- Saving/Restoring Dynamically Created Tree Nodes


I'm utilizing the jQuery widget jqTree as both navigation and also for the assembly of nested elements created dynamically. It is full-featured and one of the better components of its sort in the jQuery-verse that I have seen:

https://github.com/mbraak/jqTree

But I'm not able to leverage its setState for saving dynamically created nodes and especially when a page refreshes. I hate using Github "issues" for forum-like, quasi-canonical questions like this, so I turn to you all.

I am using forms to both save specific data about my web app, but also to leverage part of the results from that form to populate an instance of jqTree with new tree nodes and/or children. That's a very straightforward process, utilizing jqTree's native functions addNodeAfter and appendNode. The issue is in getting and setting those states for when the form submits and the page resets accordingly.

There is a parameter for saving the last state of open/closed nested nodes, saveState: true, that works well, but any nodes/children dynamically generated by the form during its lifecycle are destroyed when the form submits and the page refreshes. Someone does ask the developer something along those lines here:

https://github.com/mbraak/jqTree/issues/301

But the closest I get to an answer there is this quote:

You can use the functions getState and setState to save the state of the tree.

var state = $('#tree1').tree('getState');

$('#tree1').tree('setState', state);

If I run getState on addNodeAfter I get a console.log() result like:

{"open_nodes":[1],"selected_node":[4]}

With the same selected/created node scenario for setState, I get in the console:

{"type":"tree","timeStamp":1440016021305,"jQuery111307363375960849226":true,"isTrigger":3,"namespace":"refresh","namespace_re":{},"target":{"jQuery111307363375960849226":16}}

i.e. an almost completely different response without any direct relationship, as far as I can see, in their nomenclature.

And, if I try to submit my form and simultaneously save my new node data:

               ('form').on('submit', function(e){
                    var state = $tree.tree('getState');
                    var savedstate = $tree.tree('setState', state);

                    console.log(state);
                    console.log(savedstate);
                    //e.preventDefault();
                });

I neither get the data saved nor get any console example. Note the commented-out e.preventDefault(); statement -- comment that back in and I do get those two, very different results in the console, but, of course, my form won't trigger and as far as I can see no data is saved.

SO -- I guess I have two questions:

1.) What is the relationship between these two very different results from getState and setState in jqTree? And:

2.) How can I submit a form, save the newly created tree nodes and have them re-populate the tree when the page reloads?

Apologies for going on at length here -- thanks for your attention and any assistance you may be able to provide.


Solution

  • The answer, per jqTree's developer Marco Braak (you've gotta hope he's a Space Ghost: Coast to Coast fan), is not in using getState or setState but leveraging jqTree's toJson method and, for my purposes, local storage (or localStorage, if you insist). When the form is submitted, everything goes to local storage via toJson:

                   $('form').on('submit', function(e){
                        var tree_json = $('#tree1').tree('toJson');
                        localStorage.setItem('treeData', tree_json);
                    });
    

    No need to stringify it, either. When the page loads, it checks for any instance of treeData in local storage and builds out the tree from that -- if not, it does a fresh draw from a separate AJAX call:

                        if (localStorage.getItem("treeData") === null) {
                                $('#tree1').tree({
                                data: data,
                                autoOpen: true,
                                dragAndDrop: true,
                                saveState: true,
                                onCreateLi: function(node, $li) {
                                    $li.attr('id', node.id);
                                }
                            });
                        } else {
                                var savedTree = JSON.parse(localStorage.getItem('treeData'));
                                $('#tree1').tree({
                                    data: savedTree,
                                    autoOpen: true,
                                    dragAndDrop: true,
                                    saveState: true,
                                    onCreateLi: function(node, $li) {
                                        $li.attr('id', node.id);
                                }
                            });
                        }
    

    And saveState: true maintains the state of open and closed nodes accordingly. Works like a charm -- thanks Marco!