Skip to content
Martin@MBP edited this page Oct 20, 2014 · 30 revisions

About Fancytree persistence extension.

Store and restore tree status using cookies:

  • Store key of active and focused node as cookie.
  • Store key list of expanded and selected nodes as cookie.
  • Restore tree state from cookies when page is reloaded.

Options

  • cookieDelimiter, type: {string}, default: '~'
    Character used to join key strings.

  • cookiePrefix, type: {string}, default: 'fancytree-<treeId>-'
    Used to generate storage keys.

  • cookie, type: {object}, default: use a session cookie
    Options passed to $.cookie plugin (only if cookies are used; see also 'store' option).

  • expandLazy, type: {object}, default: use a session cookie
    true: recursively expand and load lazy nodes.

  • overrideSource, type: {boolean}, default: false
    Options passed to $.cookie plugin.

  • store, type: {string}, default: 'auto'
    Storage type 'local': localStorage, 'session': sessionStorage, 'cookie': use $.cookie plugin.
    'auto': use sessionStorage if available, fallback to cookie.
    Use 'local' (or 'cookie' with expiration settings) to store status over sessions.

  • types, type: {string}, default: 'active expanded focus selected'
    Which status types to store.

Events

(n.a.)

Methods

  • {void} tree.clearCookies(types)
    Reset persistence data.
    {string} [types='active expanded focus selected']

Example

In addition to jQuery, jQueryUI and Fancytree, include jquery.cookie.js and jquery.fancytree.persist.js:

  <script src="//code.jquery.com/jquery-1.11.1.min.js" type="text/javascript"></script>
  <script src="//code.jquery.com/ui/1.11.1/jquery-ui.min.js" type="text/javascript"></script>
  <script src="js/jquery.cookie.js" type="text/javascript"></script>
  <link href="skin-win8/ui.fancytree.css" rel="stylesheet" type="text/css">
  <script src="js/jquery.fancytree.js" type="text/javascript"></script>
  <script src="js/jquery.fancytree.persist.js" type="text/javascript"></script>

Enable persist extension and pass options:

$("#tree").fancytree({
  extensions: ["persist"],
  checkbox: true,
  persist: {
    // Available options with their default:
    cookieDelimiter: "~",    // character used to join key strings
    cookiePrefix: undefined, // 'fancytree-<treeId>-' by default
    cookie: { // settings passed to jquery.cookie plugin
      raw: false,
      expires: "",
      path: "",
      domain: "",
      secure: false
    },
    expandLazy: false, // true: recursively expand and load lazy nodes
    overrideSource: false,  // true: cookie takes precedence over `source` data attributes.
    store: "auto",     // 'cookie': use cookie, 'local': use localStore, 'session': use sessionStore
    types: "active expanded focus selected"  // which status types to store
  },
  [...]
});

Clear all status types:

$("#tree").fancytree("getTree").clearCookies();
// only selection data:
$("#tree").fancytree("getTree").clearCookies("selected");

Persistence in a lazy world

If the tree uses lazy loading, things may get complicated. For example it may not be possible to re-activate a node on page reload, if this node is not part of the initial tree.
In this case we have to load all parent nodes before.

Two options are available:

  1. Use the expandLazy option to re-load nested nodes.
  2. Let the server evaluate the list of expanded nodes and return data accordingly.
1. Use the expandLazy option

Note This option is great way for lazy programmers to flood a server with ajax requests ;-). Consider also the next section.
Note This option requires that all nodes (includng the lazy responses) have unique, reproducible keys.

$("#tree").fancytree({
  extensions: ["persist"],
  persist: {
    expandLazy: true, // true: recursively expand and load lazy nodes
    overrideSource: true,  // true: cookie takes precedence over `source` data attributes.
    ...
  },
  [...]
});
2. Let the server evaluate the list of expanded nodes

Give this tree

$("#tree").fancytree({
  extensions: ["persist"],
  persist: {
    expandLazy: false,
    overrideSource: false,
    store: "cookie", // force using cookies!
    ...
  },
  source: {
    url: "getTreeNodes",
    data: {rootKey: "root"}
  }, 
  lazyLoad: function(event, data){
    url: "getTreeNodes",
    data: {rootKey: data.node.key}
  }, 
  [...]
});

we could let the server handle persistence (pseudo code, based on Python and CherryPy).

The server reads the key list of expanded nodes from the cookie and adds these child nodes to the response:

def get_child_data_list(node_key, expanded_key_list):
    """Return an array of child definitions for a given parent key."""
    # Read `node` objects from our database
    child_node_list = get_child_nodes(node_key)
    # Convert nodes to an array of Fancytree data dicts
    result_list = []
    for node in child_node_list:
        data = {"title": node.name, 
                "key": node.guid,
                "lazy": True}
        # If a node is listed in the cookie as expanded, also load its children
        # recursively
        if node.guid in expanded_key_list:
            data["expanded"] = True
            data["children"] = get_child_data_list(node.guid, expanded_key_list)
        result_list.append(data)
            
    return result_list

@cherrypy.exposed
def getTreeNodes(rootKey):
    """This is the web service handler, called by Fancytree's `lazyLoad`."""
    if rootKey == "root":
        # Client requests initial top level nodes: also deliver expanded children
        expanded_key_list = get_cookie_value("fancytree-1-expanded").split("~")
    else:
        # Client requests children of a lazy node
        expanded_key_list = []
    # Get the (potentially nested) array of child node definitions
    result_list = get_child_data_list(rootKey, expanded_key_list)
    # and return the result as JSON
    return to_json(result_list)

Recipes

[Howto] ...
Clone this wiki locally