Dynatree is a dynamic JavaScript tree view control with support for checkboxes, drag'n'drop, and lazy loading.
Main features:
Dynatree runs best, when the HTML document is rendered in a strict mode like
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
.
Avoid the quirks mode.
You can download the current dynatree package at
http://code.google.com/p/dynatree/downloads.
It contains everything needed including the source, some documentation and examples.
jQuery is already included, but you can check the jQuery site
for the latest versions of jquery.js and ui.core.js.
This documentation contains script examples and links.
See also the Example Browser for some more advanced live demos.
Using the [View source code]
link in the
Example Browser is probably the best way to learn about Dynatree.
Let's start with a simple example:
<html> <head> <!-- Include the required JavaScript libraries: --> <script src='jquery/jquery.js' type="text/javascript"></script> <script src='jquery/jquery-ui.custom.js' type="text/javascript"></script> <script src='jquery/jquery.cookie.js' type="text/javascript"></script> <link rel='stylesheet' type='text/css' href='skin/ui.dynatree.css'> <script src='jquery.dynatree.js' type="text/javascript"></script> <!-- Add code to initialize the tree when the document is loaded: --> <script type="text/javascript"> $(function(){ // Attach the dynatree widget to an existing <div id="tree"> element // and pass the tree options as an argument to the dynatree() function: $("#tree").dynatree({ onActivate: function(node) { // A DynaTreeNode object is passed to the activation handler // Note: we also get this event, if persistence is on, and the page is reloaded. alert("You activated " + node.data.title); }, persist: true, children: [ // Pass an array of nodes. {title: "Item 1"}, {title: "Folder 2", isFolder: true, children: [ {title: "Sub-item 2.1"}, {title: "Sub-item 2.2"} ] }, {title: "Item 3"} ] }); }); </script> </head> <body> <!-- Add a <div> element where the tree should appear: --> <div id="tree"> </div> </body> </html>
As an alternative, it is possible to leave away the children
option and
add a <ul> inside the <div id="tree"> tag instead.
See Initializing the tree structure from a <ul> element for an example.
I am going into more details in the following sections.
Dynatree is based on and made for jQuery. If you are not familiar with this, you might also want to check the jQuery documentation.
The tree is initialized in the onload event of the html document. In jQuery this is usually done by passing a function to $(..) :
<head> <script type="text/javascript"> $(function(){ […] }); </script> </head>
The dynatree widget is then attached to an empty <div > element with a given ID of 'tree'.
This id can have any value, it only has to match the jQuery selector, in our case '#tree'.
Options are passed to the dynatree() function as a dictionary in curly braces:
$("#tree").dynatree({ […] });
Tree options are passed as plain JavaScript objects in curly braces, e.g.
{ … }
.
The following script shows the available options.
All options have a reasonable default, so we may only have to pass the onActivate
handler.
$("#tree").dynatree({ title: "Dynatree", // Tree's name (only used for debug outpu) minExpandLevel: 1, // 1: root node is not collapsible imagePath: null, // Path to a folder containing icons. Defaults to 'skin/' subdirectory. children: null, // Init tree structure from this object array. initId: null, // Init tree structure from a <ul> element with this ID. initAjax: null, // Ajax options used to initialize the tree strucuture. autoFocus: true, // Set focus to first child, when expanding or lazy-loading. keyboard: true, // Support keyboard navigation. persist: false, // Persist expand-status to a cookie autoCollapse: false, // Automatically collapse all siblings, when a node is expanded. clickFolderMode: 3, // 1:activate, 2:expand, 3:activate and expand activeVisible: true, // Make sure, active nodes are visible (expanded). checkbox: false, // Show checkboxes. selectMode: 2, // 1:single, 2:multi, 3:multi-hier fx: null, // Animations, e.g. null or { height: "toggle", duration: 200 } noLink: false, // Use <span> instead of <a> tags for all nodes // Low level event handlers: onEvent(dtnode, event): return false, to stop default processing onClick: null, // null: generate focus, expand, activate, select events. onDblClick: null, // (No default actions.) onKeydown: null, // null: generate keyboard navigation (focus, expand, activate). onKeypress: null, // (No default actions.) onFocus: null, // null: set focus to node. onBlur: null, // null: remove focus from node. // Pre-event handlers onQueryEvent(flag, dtnode): return false, to stop processing onQueryActivate: null, // Callback(flag, dtnode) before a node is (de)activated. onQuerySelect: null, // Callback(flag, dtnode) before a node is (de)selected. onQueryExpand: null, // Callback(flag, dtnode) before a node is expanded/collpsed. // High level event handlers onPostInit: null, // Callback(isReloading, isError) when tree was (re)loaded. onActivate: null, // Callback(dtnode) when a node is activated. onDeactivate: null, // Callback(dtnode) when a node is deactivated. onSelect: null, // Callback(flag, dtnode) when a node is (de)selected. onExpand: null, // Callback(flag, dtnode) when a node is expanded/collapsed. onLazyRead: null, // Callback(dtnode) when a lazy node is expanded for the first time. onCustomRender: null, // Callback(dtnode) before a node is rendered. Return a HTML string to override. onCreate: null, // Callback(dtnode, nodeSpan) after a node was rendered for the first time. onRender: null, // Callback(dtnode, nodeSpan) after a node was rendered. postProcess: null, // Callback(data, dataType) before an Ajax result is passed to dynatree. // Drag'n'drop support dnd: { // Make tree nodes draggable: onDragStart: null, // Callback(sourceNode), return true, to enable dnd onDragStop: null, // Callback(sourceNode) // Make tree nodes accept draggables autoExpandMS: 1000, // Expand nodes after n milliseconds of hovering. preventVoidMoves: true, // Prevent dropping nodes 'before self', etc. onDragEnter: null, // Callback(targetNode, sourceNode) onDragOver: null, // Callback(targetNode, sourceNode, hitMode) onDrop: null, // Callback(targetNode, sourceNode, hitMode) onDragLeave: null // Callback(targetNode, sourceNode) }, ajaxDefaults: { // Used by initAjax option cache: false, // false: Append random '_' argument to the request url to prevent caching. timeout: 0, // >0: Make sure we get an ajax error for invalid URLs dataType: "json" // Expect json format and pass json object to callbacks. }, strings: { loading: "Loading…", loadError: "Load error!" }, generateIds: false, // Generate id attributes like <span id='dynatree-id-KEY'> idPrefix: "dynatree-id-", // Used to generate node id's like <span id="dynatree-id-<key>">. keyPathSeparator: "/", // Used by node.getKeyPath() and tree.loadKeyPath(). cookieId: "dynatree", // Choose a more unique name, to allow multiple trees. cookie: { expires: null // Days or Date; null: session cookie }, // Class names used, when rendering the HTML markup. // Note: if only single entries are passed for options.classNames, all other // values are still set to default. classNames: { container: "dynatree-container", node: "dynatree-node", folder: "dynatree-folder", empty: "dynatree-empty", vline: "dynatree-vline", expander: "dynatree-expander", connector: "dynatree-connector", checkbox: "dynatree-checkbox", nodeIcon: "dynatree-icon", title: "dynatree-title", noConnector: "dynatree-no-connector", nodeError: "dynatree-statusnode-error", nodeWait: "dynatree-statusnode-wait", hidden: "dynatree-hidden", combinedExpanderPrefix: "dynatree-exp-", combinedIconPrefix: "dynatree-ico-", hasChildren: "dynatree-has-children", active: "dynatree-active", selected: "dynatree-selected", expanded: "dynatree-expanded", lazy: "dynatree-lazy", focused: "dynatree-focused", partsel: "dynatree-partsel", lastsib: "dynatree-lastsib" }, debugLevel: 1 // 0:quiet, 1:normal, 2:debug });
Details:
dictionary
, default: $.ui.dynatree.defaults.classNames
.$("#tree1").dynatree({ checkbox: true, // Override class name for checkbox icon: classNames: {checkbox: "dynatree-radio"}, [...]
integer
, default: 3
.boolean
, default: false
.cookie
option.
A tree structure is made of nodes. Every node may in turn contain
a list child nodes.
A dynatree always has exactly one root node, and all top level nodes
of our tree are created as direct descendants.
The root node is usually hidden, so we only see the nodes that we have added.
Dynatree can read it's structure from different sources:
children
option is passed, it will be used.
initAjax
option is passed, it will be used.
initId
option is passed, it will be used.
Methods 1-3 expect a list of node options, as described in the following sections.
Node options are defined as plain JavaScript objects in curly braces, e.g.
{ … }
.
Most of the time we pass a list of node options like this
children: [ { … }, { … }, … ]
.
The follwing snippet shows the attributes that can be used to define a tree node.
There are reasonable default values for all options, so we may only have to pass a title
.
children: [ { title: null, // (required) Displayed name of the node (html is allowed here) key: null, // May be used with activate(), select(), find(), ... isFolder: false, // Use a folder icon. Also the node is expandable but not selectable. isLazy: false, // Call onLazyRead(), when the node is expanded for the first time to allow for delayed creation of children. tooltip: null, // Show this popup text. href: null, // Added to the generated <a> tag. icon: null, // Use a custom image (filename relative to tree.options.imagePath). 'null' for default icon, 'false' for no icon. addClass: null, // Class name added to the node's span tag. noLink: false, // Use <span> instead of <a> tag for this node activate: false, // Initial active status. focus: false, // Initial focused status. expand: false, // Initial expanded status. select: false, // Initial selected status. hideCheckbox: false, // Suppress checkbox display for this node. unselectable: false, // Prevent selection. // The following attributes are only valid if passed to some functions: children: null // Array of child nodes. // NOTE: we can also add custom attributes here. // This may then also be used in the onActivate(), onSelect() or onLazyTree() callbacks. }, […] ]
The node options are also passed to the event handlers and can be accessed like this:
onActivate: function(node) { alert("You activated " + node.data.title); },
Details:
{ title: "Pretty node", addClass: "customClass1" }or
<li data="addClass: 'customClass1'">Pretty nodecan be styled using css as
span.customClass1 a { background-color: maroon; color: yellow; }
DynTreeNode.addChild()
.
unselectable
.
<div id="tree"><ul> <li class="expanded folder">Search engines <ul> <li><a href="http://www.google.com" target="_self">Google</a> <li><a href="http://www.bing.com">Bing</a>
tree.activateKey()
.dynatree-id-1234
.hideCheckbox
.
To override the node attribute defaults, modify the structure before initializing dynatree:
<script type="text/javascript"> $.ui.dynatree.nodedatadefaults["icon"] = false; // Turn off icons by default $(function(){ $("#tree").dynatree({ rootVisible: false, [...]
When a node is of type folder, it get's a special folder icon and class name.
We usually use them to hold child nodes.
Also, folders can be expanded by clicking the title text (this behavior
can be controlled using the clickFolderMode
option).
Non-folders ('documents') may also contain child nodes.
Clicking on a child node activates it, so we have to click the small [+] icon in front to expand such a document node.
In the quick example above we have already seen how a tree is initialized by passing a
node array with the children
option.
$("#tree").dynatree({ children: [ … ], […] });
See also Node options.
Instead of passing an array of data objects, we can pass a url in the initAjax
option that will be used to contact an Ajax web service.
$("#tree").dynatree({ initAjax: {url: "/ajaxTree", data: {key: "root", // Optional arguments to append to the url mode: "all" } }, […] });
The web service is expected to return a valid JSON
node list, formatted like this:
[ { ... }, { ... }, ... ]
.
Because the data request is performed asynchronously, the document will load faster. Dynatree will display a spinning wheel, while waiting for the request to complete.
See Loading child nodes on demand for details.
See Persistence for lazy trees for a sample on
how to combine this with persistence.
If the container <div>
contains a <ul>
element,
the node titles are read from the <li>
tags.
If the title contains html markup, it may be better to wrap it inside a span element.
All other node options are specified in the data
attribute of a <li> element.
For example
<li data="url: 'http://jquery.com'">jQuery home <li data="url: 'http://example.com', addClass: 'customClass1'">Example page
Note that the data
attribute is not valid in <li>
elements in
some doctypes (HTML 4.01 transitional and Strict and XHTML 1.0 Strict).
Validators will complain about this.
Also, if the id
attribute is used to pass a key, it should be
alphanumeric and start with a letter to be compliant.
(This doesn't seem to affect the functionality however.)
Nested <ul> elements are used to build a hierarchical tree structure.
After the <ul> element was parsed, it is removed from the DOM tree.
Note that <a> elements are recognized:
<li><a href='URL' target='TARGET'>TITLE</a>
will result in
node.data.title = TITLE
node.data.href = URL
node.data.target = TARGET
<head> <!-- Include the required JavaScript libraries: --> <script src='jquery/jquery.js' type="text/javascript"></script> <script src='jquery/jquery-ui.custom.js' type="text/javascript"></script> <link rel='stylesheet' type='text/css' href='skin/ui.dynatree.css' > <script src='jquery.dynatree.js' type="text/javascript"></script> <!-- Add code to initialize the tree when the document is loaded: --> <script type="text/javascript"> $(function(){ $("#tree").dynatree({ onActivate: function(node) { alert("You activated " + node); } }); }); </script> </head> <body> <!-- Add a <div> element where the tree should appear: --> <div id="tree"> <ul> <li id="key1" title="Look, a tool tip!">item1 with key and tooltip <li id="key2" class="selected">item2: selected on init <li id="key3" class="folder">Folder with some children <ul> <li id="key3.1">Sub-item 3.1 <li id="key3.2">Sub-item 3.2 </ul> <li id="key4" class="expanded">Document with some children (expanded on init) <ul> <li id="key4.1">Sub-item 4.1 <li id="key4.2">Sub-item 4.2 </ul> <li id="key5" class="lazy folder">Lazy folder </ul> </div> </body>
Finally, it is always possible to program the DynaTree and DynaTreeNode objects directly.
See also Programming dynatree.
$(function(){ // Initialize the tree in the onload event $("#tree").dynatree({ onActivate: function(node) { alert("You activated " + node); } }); // Now get the root node object var rootNode = $("#tree").dynatree("getRoot"); // Call the DynaTreeNode.addChild() member function and pass options for the new node var childNode = rootNode.addChild({ title: "Child node 1", tooltip: "This child node was added programmatically.", isFolder: true }); // childNode.addChild({ title: "Document using a custom icon", icon: "customdoc1.gif" }); });
When a user clicks a node, we want to react in some way.
So at least we want to implement an onActivate
handler.
All event handlers are passed an instance of DynaTreeNode as argument.
this
refers to the Dynatree object.
The node options can be accessed like this:
onActivate: function(node) { alert("You activated " + node.data.title); },
See also Programming dynatree.
DynaTree
callbacksthis
context is set to the tree object.tree.isUserEvent()
, tree.isInitializing()
,
and tree.isReloading()
to determine who generated this event.
onActivate: function(node) { if(node.tree.isUserEvent()){ [...] // Do something after user activated the node (using mouse or keyboard) } }
node.getEventTargetType(event)
to check which area was clicked.false
to prevent default processing
(setting focus, activate the node, expand folders, etc.).
onClick: function(node, event) { if(node.getEventTargetType(event) == "title"){ [...] // Handle the click event return false;// Prevent default processing } }
onCreate: function(node, nodeSpan) { $(span).click(function(e){ alert('clicked ' + node); }); }(Note that the use of jQuery live events may often be a more efficient solution.)
opts.onRender
.
onCustomRender: function(node) { return "<span class='dynatree-title'>SPAM</span>" }
node.getEventTargetType(event)
to check which area was clicked.false
to prevent default processing (currently none).
false
to prevent default processing
(generate keyboard navigation, focus, expand, activate, etc.).
false
to prevent default processing (currently none).
isError
will be true
and
addition info is passed: XMLHttpRequest, textStatus, errorThrown.
false
to prevent
this.
false
to prevent
this.
false
to prevent
this.
onRender: function(node, nodeSpan) { $(nodeSpan).find("a.dynatree-title").css("color", "red"); }See also
opts.onCreate
.
false
to cancel dragging of node.
true
to make tree nodes accept dropping of draggables.
node.appendAjax(...)
.)node.appendAjax(...)
.)
The following example handles an activation event by opening a url in a new window.
This assumes, that we have defined an additional custom attribute named
'url' in the node options, like so:
<ul> <li data="url: 'http://jquery.com'">jQuery home <li data="url: 'http://docs.jquery.com'">jQuery docs
or
children: [ { title: "jQuery home", url: "http://jquery.com" }, { title: "jQuery docs", url: "http://docs.jquery.com" },
Also, the title of the currently active node is displayed in the <span id='echoActive'> tag.
$("#tree").dynatree({ […] onActivate: function(node) { if( node.data.url ) window.open(node.data.url); $("#echoActive").text(node.data.title); }, onDeactivate: function(node) { $("#echoActive").text("-"); }, […] });
The following example writes the title of the currently focused node to the <span id='echoFocused'> element:
$("#tree").dynatree({ […] onSelect: function(flag, node) { if( ! flag ) alert("You deselected node with title " + node.data.title); var selectedNodes = node.tree.getSelectedNodes(); var selectedKeys = $.map(selectedNodes, function(node){ return node.data.key; }); alert("Selected keys: " + selectedKeys.join(", ")); }, […] });
If we use the cursor keys to walk the tree nodes, the focus changes to the next node, but the active node remains the same unless we use [Space] or [Enter].
Also, when we click on a folder node it is only focused, but not activated.
The following example writes the title of the currently focused node to the <span id='echoFocused'> element:
$("#tree").dynatree({ […] onFocus: function(node) { $("#echoFocused").text(node.data.title); }, onBlur: function(node) { $("#echoFocused").text("-"); }, […] });
Dynatree supports delayed loading of tree nodes, which means we read the child nodes only when their parent is expanded.
Because the data request is performed asynchronously, the browser will not block and is still responsive. Dynatree will display a spinning wheel, while waiting for the request to complete.
To make this happen, we have to
isLazy
option to true.
onLazyRead
callback to send an Ajax request,
create the child nodes, and set the 'ok' status.
$("#tree").dynatree({ […] onLazyRead: function(node){ node.appendAjax({url: "/sendData", data: {"key": node.data.key, // Optional url arguments "mode": "all" } }); }, […] });
Typically we would implement onLazyRead
by calling the
node.appendAjax()
function.
It expects one option object argument, as described in the documentation for
the jQuery.ajax() command.
These options are set by default:
cache: false
and dataType: "json"
.
Note that the success
and error
options
are implemented differently from the jQuery standard:
They pass different arguments and are called after the
Dynatree default processing took place.
This makes it easy to use the success
callback to apply any
custom postprocessing, for example activating a node or binding events.
$("#tree").dynatree({ […] onLazyRead: function(node){ node.appendAjax({url: "/sendData", data: {"key": node.data.key, // Optional url arguments "mode": "all" }, // (Optional) use JSONP to allow cross-site-requests // (must be supported by the server): // dataType: "jsonp", success: function(node) { // Called after nodes have been created and the waiting icon was removed. // 'this' is the options for this Ajax request }, error: function(node, XMLHttpRequest, textStatus, errorThrown) { // Called on error, after error icon was created. }, cache: false // Append random '_' argument to url to prevent caching. }); }, […] });
The web service is expected to return a valid JSON
node list, formatted like this:
[ { "title": "Node1", "isLazy": true, "key": "BC13B21636CD6D5C", … }, { … }, … ]
See Node options for a list of supported attributes.
When the response was received, appendAjax()
appends the child
nodes and calls node.setLazyNodeStatus(DTNodeStatus_Ok)
to
remove the wait icon.
Note that initAjax
is simply a special case, where the tree's
root node is loaded on startup.
See Initializing the structure from an Ajax response
for a sample to initialize the whole tree with an Ajax request.
This sample code (written in Python) shows how a server could create a response:
# Build node list as JSON formatted string: res = '[' res += '{ "title": "Node 1", "key": "k1", "isLazy": true },' res += '{ "title": "Node 2", "key": "k2", "isLazy": true },' res += '{ "title": "Node 3", "key": "k3", "isLazy": true }' # no trailing "," at the last line res += ']' # Add support for the JSONP protocol: # This means, if the request URL contains an argument '?callback=xxx', # wrap the result as 'xxx(result)' if "callback" in argDict: res = argDict["callback"] + "(" + res + ")" # Make sure, content type is JSON: start_response("200 OK", [("Content-Type", "application/json")]) # Return result (the square brackets are Python / WSGI specific): return [ res ]
See dynatree_server.py for a sample
implementation of a web server that handles this (~150 lines of Python code).
When this server is running, you can try this live example
of a lazy tree.
If we need more control, or if the server cannot provide JSON in Dynatree's
native format, we could also use jQuery.ajax()
to fetch the data, then transform it and call node.addChild()
:
$("#tree").dynatree({ […] onLazyRead: function(node){ $.ajax({ url: […], success: function(data, textStatus){ // In this sample we assume that the server returns JSON like // { "status": "...", "result": [ {...}, {...}, ...]} if(data.status == "ok"){ // Convert the response to a native Dynatree JavaScipt object. var list = data.result; res = []; for(var i=0, l=list.length; i<l; i++){ var e = list[i]; res.push({title: "" + i + ": " + e.fcurr + "-" + e.tcurr + ":" + e.ukurs, icon: false}); } // PWS status OK node.setLazyNodeStatus(DTNodeStatus_Ok); node.addChild(res); }else{ // Server returned an error condition: set node status accordingly node.setLazyNodeStatus(DTNodeStatus_Error, { tooltip: data.faultDetails, info: data.faultString }); } } }); […] });
Drag and drop functionality is enabled by defining the appropriate callbacks:
$("#tree").dynatree({ [...] dnd: { onDragStart: function(node) { /** This function MUST be defined to enable dragging for the tree. * Return false to cancel dragging of node. */ logMsg("tree.onDragStart(%o)", node); return true; }, onDrop: function(node, sourceNode, hitMode, ui, draggable) { /** This function MUST be defined to enable dropping of items on * the tree. */ logMsg("tree.onDrop(%o, %o, %s)", node, sourceNode, hitMode); sourceNode.move(node, hitMode); } } });
There are a lot more callbacks that can be used to fine tune the behaviour. Check the source code in the samples in the Example Browser to learn more.
When initializing a tree in persist mode, we first check, if persistence
cookies already exist.
If not, we assume first-time initializing, read the status from the tree source,
and store it into new cookies.
Otherwise we assume re-loading, ignore the source node attributes and override them using the cookie info.
In either case, the 'active', 'expand' and 'select' status of a node is read from
the data or restored from the cookies.
However, no onQueryActivate, onActivate, onExpand, onSelect, etc. events are fired.
(The only event that may be fired is onFocus.)
In order to generate these events on reload, we may use the callback function onPostInit()
and tree.reactivate().
$("#tree").dynatree({ […] onPostInit: function(isReloading, isError) { // 'this' is the current tree // isReloading is true, if status was read from existing cookies // isError is only used in Ajax mode // Fire an onActivate() event for the currently active node this.reactivate(); }, onActivate: function(node) { // Use status functions to find out about the calling context var isInitializing = node.tree.isInitializing(); // Tree loading phase var isReloading = node.tree.isReloading(); // Loading phase, and reading status from cookies var isUserEvent = node.tree.isUserEvent(); // Event was triggered by mouse or keyboard $("#echoActive").text(node.data.title); },
The problem with restoring the status of a lazy tree is, that the currently active or selected nodes may not be part of the tree, when it is freshly re-loaded.
The basic idea is to leave it up to the backend web service to deliver not only the top-level nodes, but also all nodes that are required to display the current status.
For example, it may be neccessary to render 3 parent nodes, if the active node is at level # 4.
The backend may also deliver all child nodes of expanded parents.
Or in selectMode 3 (hierarchical) we may want to send all nodes, that are partly selected.
initAjax (and appendAjax) have 3 options, that make it easy to pass persistence information to the web service.
See dynatree_server.py for a sample
implementation of a web server that handles this (~150 lines of Python code).
When this server is running, you can try this live example
of a lazy tree.
$("#tree").dynatree({ […] initAjax: {url: "/ajaxTree", data: {key: key, mode: mode, filter: filter }, addActiveKey: true, // add &activeKey= parameter to URL addFocusedKey: true, // add &focusedKey= parameter to URL addExpandedKeyList: true // add &expandedKeyList= parameter to URL }, onPostInit: function(isReloading, isError) { // In lazy mode, this will be called *after* the initAjax request returned. // 'this' is the current tree // isReloading is set, if status was read from existing cookies // isError is set, if Ajax failed // Fire an onActivate() event for the currently active node this.reactivate(); }, onActivate: function(node) { // Use status functions to find out about the calling context var isUserEvent = node.tree.isUserEvent(); // Event was triggered by mouse or keyboard $("#echoActive").text(node.data.title); },
The dynatree widget provides a set of plugin methods, that can be called
directly.
For example
$("#tree").dynatree("disable");
However this plugin implementation is based on a class called DynaTree
that holds a set of DynaTreeNode
objects.
These classes expose methods that can be accessed for enhanced functionality.
For example:
// Get the DynaTree object instance: var tree = $("#tree").dynatree("getTree"); // Use it's class methods: tree.activateKey("key1234"); // Get a DynaTreeNode object instance: var node = tree.getNodeByKey("key7654"); var rootNode = $("#tree").dynatree("getRoot"); // and use it node.toggleExpand();
Besides the constructor, that is called like this:
$("#tree").dynatree({ […] });
The following methods are globally available from the ui.dynatree namespace:
$("#tree a").hover(function(){ var node = $.ui.dynatree.getNode(this); logMsg("Hover in %s", node); }, function(){ [...] });
The following methods are directly available from the plugin:
$("#tree").dynatree("option", "autoCollapse", true); $("#tree").dynatree("option", "fx", { height: "toggle", duration: 200 });
DynaTree
object.
DynaTreeNode
object of the tree.
DynaTreeNode
object that is currently active.null
.)
DynaTreeNode
objects that are currently
selected.[ ]
.)
DynaTree
class membersactiveVisible
option is set, all parents will be expanded as necessary.$("#tree").dynatreee("disable")
.
tree.disable()
.
var prevMode = tree.enableUpdate(false); [...] tree.enableUpdate(prevMode);
$.ui.dynatree.getPersistData(cookieId, cookieOpts)
.
true
, children of selected nodes
are skipped. This may be convenient in selectMode:3 (multi-hier).
true
, if the tree is in the init phase.true
, if the tree is in the init phase and persistence is on,
and the current status was read from existing cookies.true
, if the tree is processing a user event.tree.loadKeyPath("/_3/_23/_26/_27", function(node, status){ if(status == "loaded") { // 'node' is a parent that was just traversed. // If we call expand() here, then all nodes will be expanded // as we go node.expand(); }else if(status == "ok") { // 'node' is the end node of our path. // If we call activate() or makeVisible() here, then the // whole branch will be exoanded now node.activate(); }else if(status == "notfound") { var seg = arguments[2], isEndNode = arguments[3]; } });
node.render()
for details.
initAjax
option.node.render()
for details.
{name: 'TreeName', value: 'NodeKey'}
objects, where name is the 'name' attribute of the tree's <div> element.node.toDict()
for details.
fn(node)
for all nodes.DynaTreeNode
class membersnode.data.title
or node.data.tooltip
.
See also Node options.
activeVisible
option is set, all parents will be expanded as necessary.activate()
, but does not fire events.
DynaTreeNode
are allowed.var node = $("#tree").dynatree("getTree").getNodeByKey("1234"); node.addChild({title: "New Node", key: "3333"});Since the nodeData may be a nested data structure, it is possible to create a deep hierarchy with one call.
DynaTreeNode
that the new node will be inserted before. (If this parameter is null
or omitted, the new node will be appended.)
children
object.setLazyNodeStatus()
function to display the result.null
.undefined
is
is returned.
null
is returned else.null
.
null
.
null
.
true
if node has child nodes.false
if node is a leaf, i.e. has no child nodes.undefined
if this is a lazy node, that was not yet
successfully loaded.if(node.hasChildren() === false) ...
otherNode
.
otherNode
.
targetNode
.
Possible mode
:
child
: append this node as last child of targetNode.
This is the default.
To be compatble with the D'n'd hitMode, we also accept 'over'.
before
: add this node as sibling before targetNode.
after
: add this node as sibling after targetNode.
reloadChildren()
instead.
onLazyRead
event.
if callback
is passed, it is called after the Ajax request
was executed.
Example node.reloadChildren(function(node, isOk){ if(!isOk) alert("Node " + node + " could not be reloaded."); });
useEffects
:includeInvisible
:mode
:
expand
: Expand this node after ms microseconds.
activate
: Activate this node after ms microseconds.
cancel
: cancel pending action, if any was scheduled.
DTNodeStatus_Loading
: show a spinning wheel, with 'loading...' message.
DTNodeStatus_Error
: show an error icon and message.
DTNodeStatus_Ok
: Remove the status node.
strings.loading
and strings.loadError
options.
cmd
: optional compare function. If ommitted sorting is done by node titles.deep
: optional: pass true to sort all descendant nodes.// Custom compare function (optional) that sorts case insensitive var cmp = function(a, b) { a = a.data.title.toLowerCase(); b = b.data.title.toLowerCase(); return a > b ? 1 : a < b ? -1 : 0; }; node.sortChildren(cmp, false);
recursive
: set to true, to include child nodes.callback
: (optional) function to allow modifications.var cb = node.toDict(true, function(dict){ dict.title = "Copy of " + dict.title; delete dict.key; // prevent duplicate keys });
fn(node)
for all child nodes.fn(node)
for all parent nodes.The follwing code snippets should give an idea on how to use the API.
$("#tree").dynatree("getTree").selectKey("1234"); // or another way: $("#tree").dynatree("getTree").getNodeByKey("1234").select(); // .. or yet another way (if 'generateIds' option was enabled): $("#dynatree-id-1234").prop("dtnode").select();
var node = $("#tree").dynatree("getActiveNode"); if( node ){ alert("Currently active: " + node.data.title); }
$(".dynatree-partsel").each(function(){ var node = $.ui.dynatree.getNode(this); [...] });
var node = $("#tree").dynatree("getActiveNode"); node.data.title = "My new title"; node.render();
var node = $("#tree").dynatree("getActiveNode"); var childNode = node.addChild({ title: "My new node", tooltip: "This folder and all child nodes were added programmatically." });
Note: instead of passing a single child object, we could also pass an array
of such objects.
Also, the children may again contain children
attributes, thus
defining a sub tree.
// Bind hover events to the tree's <a> tags: $("#tree a").hover(function(){ var node = $.ui.dynatree.getNode(this); logMsg("Hover in %s", node); }, function(){ var node = $.ui.dynatree.getNode(this); logMsg("Hover out %s", node); });
$("#tree").dynatree("getRoot").visit(function(node){ node.expand(true); });
// Get a JavaScript object copy of the tree var dict = $("#tree").dynatree("getTree").toDict(); // ... then use Ajax to send this to your server...
http://server/_test-194.html?activate=_11
// Add a helper function to parse the URL function getURLParameter(name) { return unescape( (RegExp(name + '=' + '(.+?)(&|$)').exec(location.search)||[,null])[1] ); } // Evaluate the URL after the tree was loaded $(function(){ $("#tree").dynatree({ [...] onPostInit: function(isReloading, isError) { var key = getURLParameter("activate"); if( key ) { this.activateKey(key); } },
The tree's fonts, colors, and icons are defined using CSS, so changing the appearance is simply a matter of including a custom stylesheet or by replacing icons.gif with another version.
<script src="../jquery/jquery.js" type="text/javascript"></script> <script src="../jquery/jquery-ui.custom.js" type="text/javascript"></script> <script src="../src/jquery.dynatree.js" type="text/javascript"></script> <!-- Include the basic stylesheet: --> <link href="../src/skin-vista/ui.dynatree.css" rel="stylesheet" type="text/css"> <!-- Override CSS with a custom stylesheet : --> <link href="skin-custom/custom.css" rel="stylesheet" type="text/css" > <script type="text/javascript"> $(function(){ $("#tree").dynatree({ […] }); }); </script>
Custom.css would include lines like this:
.dynatree-has-children span.dynatree-icon { background-position: 0 0; background-image: url("doc_with_children.gif"); }
Changing the appearance and icons of single nodes is done by assigning a custom class:
<ul> <li data="addClass: 'custom1'">Document with custom class
or
children: [ { title: "Document with custom class", addClass: "custom1" },
we would then add CSS definitions for the new node to our stylesheet:
span.custom1 a { background-color: #ffffbb; color: maroon; } span.custom1 span.dynatree-icon { background-position: 0 0; background-image: url("customDoc2.gif"); }
Strings can be translated in the tree options:
$("#tree").dynatree({ […] strings: { loading: "Daten werden geladen…", loadError: "Fehler beim Laden!" }, });
I am using the planize plugin
by Nicolas Perriault for the table of contents.
I am using prettify.js
by Mike Samuel for syntax highlighting in the of source code samples.
First of all: this is work in progress.
Any kind of feedback is very welcome :-)