Need help updating this page. Describe the navigation widgets in Dojo including attributes that are common to all these widgets.
This documentation refers to 3rd major version of the tree widget, sometimes refered to as TreeV3.
Many mentioned classes (e.g TreeLoadingController) have V3 on the end, but that suffix is sometimes omitted, because it will be removed in dojo 0.5.
If there exist 2 same classes, but one with V3 at the end - it's the one you need.
Examples are given in tests (dojo/tests/widget/treeV3), so you might want to check them first and copy-paste exactly the things you need.
Please browse the Book,
then ask questions in dojo-interest list
Extensions are also called plugins, they can be hooked onto widgets in various combinations and provide wanted options.
Currently there is a couple of extensions
Tree extension, disables wrapping for tree nodes. Also it fixes IE bug when an 'unwrappable' node (e.g single word) will move to next line if no space left.
Tree extension, places icon to the left of a node, depening on nodeType property
Selector extension, highlights currently selected nodes
Selector extension, deselects a selected node when it is clicked. Usually, one should ctrl-click, or click another node.
Tree extension, turns labels into links, merges object property into tag
To make tree (or its elements) unselectable use dojo.html.disableSelection in nodeCreate and treeCreate hooks. Apply disableSelection to every node you want to make unselectable.
There is an "objectId" property and "object" property ready to be filled in from markup or program-way.
You may use dojo.lang.forEach(nodeOrTree.getDescendants(),function(elem) { ... }) to process all descendants, it will walk children property recursively.
The safer way would be to call TreeCommon.prototype.processDescendants(nodeOrTree, filter, func), it will process all children with func, but will not descend into nodes if filter(node) returns false. E.g see collapseAll controller method uses it to collapse all widgets, but skip non-folders and data objects.
Make a single root node with actionsDisabled="DETACH;MOVE". User will be unable to remove it, so interface will stay sane.
Also, you may want to set actionsDisabled="ADDCHILD" to tree itself, so now children can be added besides the root.There are 2 ways. The first one is to attach TreeSelector and hook on "select" event. So when a user clicks, event handler will change url to node.object.href. Of course, you should fill hrefs.
A probably more convinient path would be to employ TreeLinkExtension, which will turn your labelNodes into real links, and apply attrbutes from node object to them.
Dojo performs actions not only when a node is created, but also cleanup when a node is destroyed. Lazy features allow node creation be distributed in time, but when you navigate away from a large tree, large cleanup causes visible delay. I don't know a way to evade that.
TreeDocIconExtension handles that. You should declare nodeType for your nodes, so they'll get nodeIcon[Your type] CSS class. Default type is Document for leaves and Folder for folders.
There is also setNodeTypeClass method to update node CSS when its nodeType changes e.g programmatically.
This documentation refers to 3rd major version of the tree widget, sometimes refered to as TreeV3.
Many mentioned classes (e.g TreeLoadingController) have V3 on the end, but that suffix is sometimes omitted, because it will be removed in dojo 0.5.
If there exist 2 same classes, but one with V3 at the end - it's the one you need.
Examples are given in tests (dojo/tests/widget/treeV3), so you might want to check them first and copy-paste exactly the things you need.
Please browse the Book,
then ask questions in dojo-interest list
Note: most classes here omitt 'V3' suffix
Previous tree used a list of divs, each of them was indented with grid and spacers to right level. The new tree uses natural nested divs structure (children' divs inside parent's div). Grid is contigous and structure is displayed correctly for any node/font size
All image and size information was removed from JS code. There is a bunch of classes applied to nodes, that may denote node folder state, node type, show if there are children, etc. CSS moves this logical classes into style
Different trees be styled with different CSS class families
Want to put 2 differently styled trees on a page? Give them different classPrefix.
Rich content support was incomplete, because list-of-divs model could not handle arbitrary-sized nodes. Now you may have <br>, <p> and any other width/height
modifiers.
nodeDOMCreated event was removed. That's because listeners are bound to tree and may want to modify the new node, but that's only possible when the node is being bound to the tree, not when it was created and hanging around. afterTreeChange was introduced to help listeners to (un)bind nodes the right moment.
All events were renamed to better reflect the moment of their publishing.
afterExpand, afterCollapse events now fire when the animation (e.g fading in or out) finishes, not when the actual expand/collapse is called.
Before TreeV3, all nodes must be widgets. A node is added - hence graphical widget is created. For performance reasons that behavior was altered. Now when you add a node, you may actually add a "data object", containing node data, e.g {title:"new node"}. You may want to add a large nested branch of such data objects, like {title:"new", children:[...data objects..]}.
Data objects will become real members of children array (you may recursively search them, modify etc), but graphical widgets will be created only when visitor expands them.
The compatibility drawback of such behavior is that old code may erroneously call widget methods on data objects while recursively traversing a tree, e.g with Widget#getDescendants. You should change such code to use TreeCommon#processDescendants, or handle data objects in special way.
There are no special mechanisms to add laziliy instantiated "data objects". You may manipulate them simply modifying children array, but no events are thrown until a real widget appears on the scene. In most cases that is fine, but you are free to "disable" lazy widget creation - do not modify children directly and enable tree.eagerWidgetInstantiation
The Tree is actually a pack of loosely coupled components, connected through events. To keep things simple and also for compatibility reasons, such components(controller,selector...) were created implicitly, if not declared. But actually this proved to be a source of questions and misunderstandings. So now nothing is created implicitly, read how-to and declare things.
Old callbacks code was removed in favor to dojo.Deferred. Now all operations may be async and run your callbacks at the end.
Sounds simple enough.. Select multiple nodes with ctrl and get them with selector.selectedNodes. instead of removed selectorNode call.
Currently, multiple drag'n'drop does not work with multiple selection because of dojo bugs. Hopefully will be fixed.
If treeNode property is empty, tree will create a new node from the data returned by source.getTreeNode, then source.onDrop will be called to remove old node.
It became possible to edit nodes inline, using TreeEditor. Base variant uses RichText widget, you can make another wrapper though. Remote calls can be made on save only, or on start/cancel too e.g for locking purposes.
Author: IlyaThere are few code paths that lead to same purpose: to create a tree node. They differ in effeciency and use patterns
You specity a tree and its nodes in HTML, relying upon dojo to parse it and turn into widgets. That is a slowest way, but nice for small trees or if only tree top is specified and the rest is created later.
dojo widget parser walks DOM and creates a special structure. The next pass creates widgets from the structure.
The generic widget creation routine. It basically runs the operations in order:
Note that initialize is called in pre-order: parent is initialized before children, postInitialize is called in post-order: a child is postCreated before its parent.
If you create nodes with javascript, then you run create calls manyally. So parents are naturally created (and postCreated) before children.
There seem to be no good way to distinguish betwen markup creation and manual creation. From the one hand its seems good, because allows reuse of generic creation code. From the other hand code paths going through this code are subtly different.
The reliable thing is that initialize will process widget after its domNode is built, BUT it should not assume anything about children.
afterChangeTree event is fired on initialization also. If you want to know anything about children and do something at this point - check addChild, but not node creation.
children array may be
Tree was coded with performance in mind. Although, JavaScript itself is a slow language. Flexible model requires some code that slows it down. It's not DOM manipulations, but actually javascript that I couldn't make lighter. Being a part of dojo/widget structure implies some overhead, but also power.
Almost all operations require small constant time when single node is involved. Depending on your application you may notice slowdown when (most common) creating lots of nodes or performing other batch operations.
Creation from markup or with standard create/addChild routines is 2-3 times slower, because these routines are generic.
Fast node creation with dojo tree is 2-3 times slower than xtree 1.7, another tree widget, not so featured, but nicely optimized for performance.
The results described here refer to operations without any lazy features involved. Most of time you will use lazy creation or lazy loading, or both, and operate with thousands of "virtual" nodes with ease.
When talking about performance, one should understand, that there are single-node operations that operate on single node... These ones are fast. The examples are: create a node, delete a node, move a node along the tree.
... And there are batch operations that touch a lot of nodes. The examples are: initial tree creation, moving a node from one tree to another which has different listeners, etc.
That performance issues become noticeable at 100-300 tree nodes depending on your trees. All algorithms are linear in worst case, but JS is slow language, DOM is also not that fast.
There is a number of features one could use to get a speedup.
A node can be created with isFolder=true flag, but without children. Any node has a state, initially UNCHECKED for empty folder, and used by TreeLoadingController.
When a user presses expand, tree controller (supporting lazy loading) will send a request to server asking for nodes, and parse the answer creating children.
The benefit is obvious: you don't have to load/process whole tree at once. You can only load a single node and user will load the rest clicking "expand"
Node/tree keeps array of its children in children property. Lazy creation is somewhat a half-way approach to lazy loading. It allows you to put data objects into this array and tree will create widgets of them later, when they are expanded.
For instance, one can call node.children = [{title:'node1'},{title:'node2'}]. The objects will be set, but no widgets are created. You can also set children to nested array: node.children = [{title:'node1', children:[{title:'node2'}] }].
You can create tree on server, JSON-serialize it and put to HTML, that is gzip-compressed. Compression will be 6 times or more, so it is not that space hungry.
The benefit comes from postponing almost all real job: widget creation and attaching it to tree will happen in expansion-time.
Sometimes, lazy creation and loading may work together nicely, providing seamless increase in speed and decrease in memory footprint. For instance, server may pass a whole tree branch in JSON to lazy loading controller. Top nodes will be created right along, because user needs them, but the rest of the branch will be postponed relying on lazy creation feature.
There are operations, like "expandAll" where such lazy tricks don't help, because all graphical widgets must be processed. That is why widget creation process is well-optimized itself. createSimple is a hacky program-only way to create TreeNodes fast. setChildren is a method to assign (and create if needed) all children at once. It helps to evade some extra work happening when children are added one by one.
IE has a well-known bug. If an image was loaded dynamically - with a new Image(), or img.src= assignment, or even as a background of a new node, it will not be cached. So every time when you create a node, all needed icons get loaded from server (or requested at least). A possible solution is to put a special div into HTML (adjust src to your path):
<div style="display:none">
<!-- IE has a bug: it reloads all dynamically resolved images, no matter, is it
new Image() or CSS background. If you don't specify images like that,
it will reload them every time a new node is created -->
<img src="../../../src/widget/templates/images/TreeV3/i.gif"/>
<img src="../../../src/widget/templates/images/TreeV3/i_half.gif"/>
<img src="../../../src/widget/templates/images/TreeV3/expand_minus.gif"/>
<img src="../../../src/widget/templates/images/TreeV3/expand_plus.gif"/>
<img src="../../../src/widget/templates/images/TreeV3/expand_leaf.gif"/>
<img src="../../../src/widget/templates/images/TreeV3/i_long.gif"/>
<img src="../../../src/widget/templates/images/TreeV3/document.gif"/>
<img src="../../../src/widget/templates/images/TreeV3/open.gif"/>
<img src="../../../src/widget/templates/images/TreeV3/closed.gif"/>
</div>
Author: Ilia
To talk with server, one should use TreeLoadingControllerV3 or TreeRpcControllerV3. They inherit from TreeBasicControllerV3 and override its methods to deliver remote calls possibility.
TreeLoadingControllerV3 contains main methods for server calls, and allows dynamic node loading. TreeRpcControllerV3 adds server calls to tree manupulations like "createChild/move/edit...".
There are many classes of events, published with dojo.event.publish mechanism. Every event has a name and message object, containing more precise information about what happened. You may use events to update your data while tree changes, and to perform additional processing of involved objects.
There is a default naming scheme for an event class. E.g for a tree with widgetId='mytree', event of class afterTreeCreate will be named "mytree/afterTreeCreate". You may provide other names in eventNames property of the tree.
Event occurs after tree creation is complete. There is an alternative to hook on this action by putting your objects in "listeners" property of the tree. The difference is that listeners are guaranteed to hook before nodes get added, and afterTreeCreate is published after Tree widget is created.
references to tree
Published right before actual Tree#destroy method is called. Useful for cleanups
references to tree
Right before TreeNode#destroy is called. Node is detached after this event fired.
references to node
This event is tightly created with node creation process. It is fired when
references previous tree, null if node has been just created
new(current) tree
target node
Fires when a node obtains "folder" state. That may happen when a first child is added to a leaf, or if a node was initially created with isFolder=true
references to node
Fires when a node obtains looses "folder" state. That may happen when a last child leaves the node, and Tree.unsetFolderOnEmptyis set, or when unsetFolder is called explicitly.
references to node
These events share same arguments and fire when a node is moved. Move process is considered something special. When you move a node, no detach/addChild events get thrown. That allows to tell situations when a node leaves a tree for some time (detached then attached) from situations when a node is simply moved to another location
previous parent
previous tree
previous index among siblings
new parent
new tree
new index among siblings
target node
Published when a node is attached to parent. This may occur at the end of creation process, or when a node is lazily instantiated from data object.
Also it occurs when a detached node gets attached.
references to node
index among siblings
current parent who adopted a child
flag is set if child was laziliy instantiated. That is: it resided as data object in children array, but user expanded its parent, so node widget came to life.
Occurs when a node is detached. This may happen in the process of node destruction. Keep in mind, that detaching a node sets its parent to null, but
tree remains same.
references to node
references to old parent
references to index among children of old parent
Fire when a node is expanded/collapsed. Some togglers do nice animation hiding/showing node. This event fires when animation finishes.
target node
When a node is edited, or explicit setTitle method is called, this event helps to inform interested parts about changes.
target node
replaced node title
There are few major approaches to building dynamic trees.
1. list of idented divs
Each tree node is a div with indentation. Indentation is e.g 20px * node depth, so everything looks fine. Usually indentation is made of many quadrantic images, each of them represents empty space or grid lines, which visibly link nodes together.nested divs.
Of course, 'div' can be changed to any tag, e.g 'li'.
2. nested divs
Divs are nested same way tree nodes are nested. Can use ul/li instead of divs, there's only symantic difference, of course, if styles are same.
Each div can be idented relatively to its parent with padding/margin property, or with images.
If we use images here, then there will be lots of extra tags, so padding/margin seems better.
Let's consider a simple tree
* Node1
* Node 1.1
* Node 1.2
* Node 2