Dynatree documentation

This document describes dynatree version: $Version: 0.5.1$.
Document revision: $Revision: 1.1 $.
A current version may be found at the project site http://wwwendt.de/tech/dynatree/index.html.

Dynatree is a dynamic JavaScript tree view control with support for checkboxes, persistence and lazy loading.

Main features:

This document describes release 0.5.
If you are updating from version 0.4 please read the migration hints first.
Also, the 0.4 documentation is still available.

Download

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.

Examples

This documentation contains script examples and links.
See also the Example Browser for some more advanced live demos.

Quick start

Let's start with a simple example:

Try this example...
<html>
<head>
	<!-- Include the required JavaScript libraries: -->
	<script src='jquery/jquery.js' type='text/javascript'></script>
	<script src='jquery/ui.core.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(dtnode) {
				// 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 " + dtnode.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.

Initializing the tree

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

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 root", // Name of the root node.
	rootVisible: false, // Set to true, to make the root node visible.
	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 }

	// 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: handle focus.
	onBlur: null, // null: handle unfocus.

	// 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.
	onLazyRead: null, // Callback(dtnode) when a lazy node is expanded for the first time.
	
	ajaxDefaults: { // Used by initAjax option
		cache: false, // false: Append random '_' argument to the request url to prevent caching.
		dataType: "json" // Expect json format and pass json object to callbacks.
	},
	strings: {
		loading: "Loading…",
		loadError: "Load error!"
	},
	idPrefix: "ui-dynatree-id-", // Used to generate node id's like <span id="ui-dynatree-id-<key>">.
    cookieId: "ui-dynatree-cookie", // Choose a more unique name, to allow multiple trees.
	cookie: { // Options passed to $.cookie (see jquery.cookie.js)
		expires: null, // Days or Date; null: session cookie
		path: undefined, // String; Defaults to current page
		domain: undefined, // String; Defaults to creator's domain
		secure: undefined // Boolean; Defaults to false
	},
    // 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: "ui-dynatree-container",
		folder: "ui-dynatree-folder",
		document: "ui-dynatree-document",
		empty: "ui-dynatree-empty",
		vline: "ui-dynatree-vline",
		expander: "ui-dynatree-expander",
		connector: "ui-dynatree-connector",
		checkbox: "ui-dynatree-checkbox",
		title: "ui-dynatree-title",
		nodeError: "ui-dynatree-statusnode-error",
		nodeWait: "ui-dynatree-statusnode-wait",
		active: "ui-dynatree-active",
		selected: "ui-dynatree-selected",
		expanded: "ui-dynatree-expanded",
		[...]
	},
	debugLevel: 1 // 0:quiet, 1:normal, 2:debug
});

Details:

classNames
Type: dictionary, default: $.ui.dynatree.defaults.classNames.
Override class names, that are used, when rendering the HTML markup.
Typically this will require some customization of the CSS file too.
Example:
$("#tree1").dynatree({
	checkbox: true,
	// Override class name for checkbox icon:
	classNames: {checkbox: "ui-dynatree-radio"},
	[...] 
clickFolderMode
Type: integer, default: 3.
Define, how a mouse click will change a folder status.
  1. Single-clicking a folder title (or pressing the [enter] or [space] key) will activate it.
    In this mode documents and folders behave the same.
  2. Single-clicking a folder title expands the node. The folder cannot be activated.
  3. Single-clicking a folder title will activate and expand it.
persist
Type: boolean, default: false.
True: the tree's expansion, activation, focus and selection state is saved to a session cookie, so reloading the page will restore the status.
Notes: this may not work with lazy nodes.
See cookie option.

Initializing the tree structure

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:

  1. If the children option is passed, it will be used.
  2. Otherwise, if the initAjax option is passed, it will be used.
  3. Otherwise, if the initId option is passed, it will be used.
  4. Otherwise, if the the container <div> element contains a <ul> element, it will be used.
  5. Otherwise, the tree is left empty.
    But we may choose to do so, if we want to modify the tree programmatically.

Methods 1-3 expect a list of node options, as described in the following sections.

Node options

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.
		addClass: null, // Class name added to the node's span tag.  
		icon: null, // (deprecated: consider using addClass) Use a custom image (filename relative to tree.options.imagePath). 'null' for default icon, 'false' for no icon.
		activate: false, // Initial active status.
		focus: false, // Initial focused status.
		expand: false, // Initial expanded status.
		select: false, // Initial selected status.
		hideCheckbox: false, // Suppress checkbox 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 onLazyRead() callbacks.
	},
	[…]
]

The node options are also passed to the event handlers and can be accessed like this:

onActivate: function(dtnode) {
	alert("You activated " + dtnode.data.title);
},

Details:

activate
If set to true, the node will be initially activated.
addClass
Class name that is added to the node's <span> element.
Example:
{ title: "Pretty node", addClass: "customClass1" }
or
<li data="addClass: 'customClass1'">Pretty node
can be styled using css as
span.customClass1 a { background-color: maroon; color: yellow; }
children
Array of node options, that are used to generate child nodes.
This option is only valid when passed to certain functions, like DynTreeNode.addChild().
expand
If set to true, the node will be initially expanded.
focus
If set to true, the node will be initially focused.
hideCheckbox
Suppress display of checkbox icon.
It is still possible to (de)select the node using the API, keyboard or initialization data. (The selection state may be visualized by a CSS style.)
See also unselectable.
icon
Optional name of an image file relative to the image directory.
If null specified, a default image is used depending on the node type (folder or document). This is the default.
If false specified, no image is displayed.
isFolder
Marks node as folder (treated as a document otherwise).
See Folders and Documents
isLazy
Enables delayed loading of the node contents. When a lazy node is expanded for the first time, the onLazyRead() callback is called.
key
Uniquely identifies this node. It is optional, but we need it for some functions like tree.activateKey().
If specified, the node's element id is generated by prepending a prefix like this: ui-dynatree-id-1234.
If not specified, a random key id is generated.
select
If set to true, the node will be initially selected.
title
Type: string, default: "".
Displayed name of the node (html markup is allowed here).
tooltip
Optional string to display in a popup window when the cursor hovers over the node.
unselectable
Prevent (de)selection of this node using API, mouse, and keyboard.
It is still possible, to (de)select this node in the initialization data or indirectly (in multi-hier mode).
See also 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,
			[...]

Folders and documents

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.

Initializing the tree structure from an object array

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.

Initializing the tree structure from an Ajax response

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 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.

Initializing the tree structure from a <ul> element

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.

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.

Try this example...
<head>
	<!-- Include the required JavaScript libraries: -->
	<script src='jquery/jquery.js' type='text/javascript'></script>
	<script src='jquery/ui.core.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(dtnode) {
				alert("You activated " + dtnode);
			}
		});
	});
	</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>

Initializing the tree structure programmatically

Finally, it is always possible to program the DynaTree and DynaTreeNode objects directly.

See also Programming dynatree.

Try this example...
$(function(){
	// Initialize the tree in the onload event
	$("#tree").dynatree({
		onActivate: function(dtnode) {
			alert("You activated " + dtnode);
		}
	});
	// 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"
	});
});

Handling events

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 node's <span> tag.
The node options can be accessed like this:

onActivate: function(dtnode) {
	alert("You activated " + dtnode.data.title);
},

See also Programming dynatree.

Handling activate/click

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.

Try this example...
$("#tree").dynatree({
	[…]
	onActivate: function(dtnode) {
		if( dtnode.data.url )
			window.open(dtnode.data.url);
		$("#echoActive").text(dtnode.data.title);
	},
	onDeactivate: function(dtnode) {
		$("#echoActive").text("-");
	},
	[…]
});

Handling selection events

The following example writes the title of the currently focused node to the <span id='echoFocused'> element:

Try this example...
	$("#tree").dynatree({
		[…]
		onSelect: function(flag, dtnode) {
			if( ! flag )
				alert("You deselected node with title " + dtnode.data.title);
			var selectedNodes = dtnode.tree.getSelectedNodes();
			var selectedKeys = $.map(selectedNodes, function(node){
				return node.data.key;
			});
			alert("Selected keys: " + selectedKeys.join(", "));
		},
		[…]
	});
	

Handling focus changes

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:

Try this example...
$("#tree").dynatree({
	[…]
	onFocus: function(dtnode) {
		$("#echoFocused").text(dtnode.data.title);
	},
	onBlur: function(dtnode) {
		$("#echoFocused").text("-");
	},
	[…]
});

Loading child nodes on demand ('lazy loading')

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

Try this example...
$("#tree").dynatree({
	[…]
	onLazyRead: function(dtnode){
		dtnode.appendAjax({url: "/sendData",
	                       data: {"key": dtnode.data.key, // Optional url arguments
		                          "mode": "all"
		                          }
		                  });
	},
	[…]
});

Typically we would implement onLazyRead by calling the dtnode.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(dtnode){
        dtnode.appendAjax({url: "/sendData",
                           data: {"key": dtnode.data.key, // Optional url arguments
                                  "mode": "all"
                                  },
                           success: function(dtnode) {
                               // Called after nodes have been created and the waiting icon was removed.
                               // 'this' is the options for this Ajax request
                               },
                           error: function(dtnode, 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 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.

Persistence

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 Ajay mode
        // Fire an onActivate() event for the currently active node
        this.reactivate();
    },
    onActivate: function(dtnode) {
        // Use status functions to find out about the calling context
        var isInitializing = dtnode.tree.isInitializing(); // Tree loading phase
        var isReloading = dtnode.tree.isReloading(); // Loading phase, and reading status from cookies
        var isUserEvent = dtnode.tree.isUserEvent(); // Event was triggered by mouse or keyboard
        
        $("#echoActive").text(dtnode.data.title);
    },     

Persistence for lazy trees

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 wss read from existing cookies
        // isError is set, if Ajax failed
        // Fire an onActivate() event for the currently active node
        this.reactivate();
    },
    onActivate: function(dtnode) {
        // Use status functions to find out about the calling context
        var isUserEvent = dtnode.tree.isUserEvent(); // Event was triggered by mouse or keyboard
        
        $("#echoActive").text(dtnode.data.title);
    },

Programming dynatree

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();

Dynatree Plugin methods

Besides the constructor, that is called like this:

$("#tree").dynatree({
	[…]
});

the following methods are directly available from the plugin:

$("#tree").dynatree("disable")
Disable event handling and add a class called 'ui-dynatree-disabled' to the container element.
$("#tree").dynatree("enable")
Enable event handling and remove the 'ui-dynatree-disabled' class from the container element.
$("#tree").dynatree("getTree")
Return the associated DynaTree object.
$("#tree").dynatree("getRoot")
Return the root DynaTreeNode object of the tree.
$("#tree").dynatree("getActiveNode")
Return the DynaTreeNode object that is currently active.
(May be null.)
$("#tree").dynatree("getSelectedNodes")
Return an array of DynaTreeNode objects that are currently selected.
(May be empty: [ ].)

DynaTree class members

activateKey(key)
Activate and focus node with a given key and fire focus and activate events.
If activeVisible option is set, all parents will be expanded as necessary.
If key is null, the current activation is removed.
Return the active DynaTreeNode.
enableUpdate(enable)
Turn rendering on or off. Disabling update may speedup processing, when adding lots of nodes.
Don't forget to turn rendering back on, after applying the changes.
getActiveNode()
Return the currently active DynaTreeNode or null.
getNodeByKey(key)
Return DynaTreeNode with a given key or 'null' if not found.
getPersistData()
Return cookie persistence info as dictionary.
There is also a global function available: getDynaTreePersistData(cookieId, cookieOpts)
getRoot()
Return the root DynaTreeNode object.
getSelectedNodes(stopOnParents)
Return a list of currently selected DynaTreeNodes (may be an empty array).
If stopOnParents is set to true, children of selected nodes are skipped. This may be convenient in selectMode:3 (multi-hier).
isInitializing()
Return true, if the tree is in the init phase.
Use this function in an event handler, to check if the event was fired during a page reload, when the cookie persistence is applied.
isReloading()
Return true, if the tree is in the init phase and persistence is on, and the current status was read from existing cookies.
Use this function in an event handler, to check if the event was fired during a page reload, when the cookie persistence is applied.
isUserEvent()
Return true, if the tree is processing a user event.
Use this function in an event handler, to check if the event was fired in response to a mouse click or key stroke.
selectKey(key, flag)
Select or deselect node with a given key and fire focus and select events.
Return the selected DynaTreeNode.
reactivate(setFocus)
Fire onQueryActivate and onActivate events for the currently active node (if there is one).
This may be useful when processing an onPostInit callback.
reloadAjax()
Reload the the tree, by re-submitting the Ajax request that was defined in the initAjax option.
toDict()
Convert the tree into a JavaScript object.
See node.toDict() for details.
visit(fn, data, includeRoot)
Call fn(dtnode, data) for all nodes.
Stop iteration of the current branch, if fn() returns false.

DynaTreeNode class members

Attribute 'data'
Use this attribute to access all node options that were passed to create this node.
For example dtnode.data.title or dtnode.data.tooltip. See also Node options.
activate()
Activate this node - according to flag - and fire a onActivate event.
If activeVisible option is set, all parents will be expanded as necessary.
Focus is not set.
addChild(nodeData[, beforeNode])
Append a new child node.
nodeData may be a node data object as defined in Node options, or an array thereof. Also objects and arrays of type DynaTreeNode are allowed.
Example:
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.
The optional argument beforeNode specifies a child DynaTreeNode that the new node will be inserted before. (If this parameter is null or omitted, the new node will be appended.)
appendAjax(ajaxOptions)
Accepts a standard jQuery Ajax option object.
An asynchronous request is started, so this function returns immediately. While loading, a spinning wheel is displayed. On error, a red icon is shown.
The request handler must return a JSON object, formatted like the data'a children object.
Use the setLazyNodeStatus() function to display the result.
See Loading child nodes on demand ('lazy loading') for details.
deactivate()
Deactivate this node and fire an onDeactivate event.
expand(flag)
Expand or collapse this node - according to flag.
focus()
Set focus to this node. Parent nodes are expanded, if this is necessary to make it visible.
getEventTargetType(event)
Return the part of a node, that a click event occurred on.
Possible values: 'prefix' 'expander', 'checkbox', 'title'.
null is returned else.
Note: there is no check, if the event was fired on this node.
getLevel()
Return the depth (i.e. number of parent nodes).
0 is returned for the root node.
hasChildren()
Return true, if this node has child nodes.
isActive()
Return true, if this is the currently active node.
isSelected()
Return true, if the node is selected.
makeVisible()
Expand all parents as neccessary, to make this node visible.
reload(force)
Discard all children of a lazy node.
If the node is currently expanded, an onLazyRead event is generated to re-load the children immediately.
If the node is collapsed, and force is false or ommited, the children will removed, but only re-loaded when the node is expanded by the user.
If the node is collapsed, and force is true, the children will be reloaded immediately (without expanding).
remove()
Remove this node from tree.
removeChildren()
Remove all child nodes.
render(bDeep)
Redraw this node (and all child nodes, if bDeep is true).
select(flag)
Select or deselect this node - according to flag - and fire an onSelect event.
setLazyNodeStatus(status)
Display a dummy child node, to provide feedback, when loading a lazy node's content.
Possible status: Messages may be customized using the strings.loading and strings.loadError options.
toDict(recursive, callback)
Convert the node into a JavaScript object.
recursive: set to true, to include child nodes.
callback: (optional) function to allow modifications.
Example
var cb = node.toDict(true, function(dict){
    dict.title = "Copy of " + dict.title;
    delete dict.key; // prevent duplicate keys
});
toggleExpand()
Toggle expansion state.
Expanding a lazy node, fires a onLazyRead event.
toggleSelect()
Toggle selection state.
visit(fn, data, includeSelf)
Call fn(dtnode, data) for all child nodes.
Stop iteration of the current branch, if fn() returns false.

Programming examples

The follwing code snippets should give an idea on how to use the API.

Example: Select a node with key '1234'

$("#tree").dynatree("getTree").selectKey("1234");
// or another way:
$("#tree").dynatree("getTree").getNodeByKey("1234").select();
// .. or yet another way:
$("#ui-dynatree-id-1234").attr("dtnode").select();

Example: Access the currently active node

var dtnode = $("#tree").dynatree("getActiveNode");
if( dtnode )
	alert("Currently active: " + dtnode.data.title);

Example: Retrieve a node using a jQuery selector

$(".ui-dynatree-partsel").each(function(){
    dtnode = $(this).attr("dtnode");
    [...]
});

Note: The selector must evaluate to the node's <span> tag.

Example: Rename the active node

var dtnode = $("#tree").dynatree("getActiveNode");
dtnode.data.title = "My new title";
dtnode.render();

Example: Add a child to the active node

var dtnode = $("#tree").dynatree("getActiveNode");
var childNode = dtnode.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.

Example: Add a hover handler and find the hovered node from any sub element

// Bind hover events to the tree's <a> tags:
$("#tree a").hover(function(){
		// Find dtnode object for this <a> tag
		var dtnode = $(this).parent("[dtnode]").attr("dtnode");
		// (...) for example open a tooltip.
	}, function(){
		// (...) for example remove the tooltip.
	}); 

Example: Expand all nodes

$("#tree").dynatree("getRoot").visit(function(dtnode){
    dtnode.expand(true);
});

Example: Save current tree status to the backend

// Get a JavaScript object copy of the tree
var dict = $("#tree").dynatree("getTree").toDict();
// ... then use Ajax to send this to your server...

Theming and translation

The tree's fonts, colors, and icons are defined using CSS, so changing the appearance is simply a matter of including a custom stylesheet.

Try this example...
<script src='../jquery/jquery.js' type='text/javascript'></script>
<script src='../jquery/ui.core.js' type='text/javascript'></script>
<script src='../src/jquery.dynatree.js' type='text/javascript'></script>
<!-- Include a customized stylesheet: -->
<link href='custom-skin/ui.dynatree.css' rel='stylesheet' type='text/css' >

<script type='text/javascript'>
	$(function(){
		$("#tree").dynatree({
			[…]
		});
	});
</script>

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: maroon;
	color: yellow;
}
span.custom1 span.ui-dynatree-icon
{
	background-image: url("doc_with_children.gif");
}

Strings can be translated in the tree options:

$("#tree").dynatree({
	[…]
	strings: {
		loading: "Daten werden geladen…",
		loadError: "Fehler beim Laden!"
	},
});

Feedback, version history, credits and known issues

Credits

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.

Feedback

First of all: this is work in progress.
Any kind of feedback is very welcome :-)