jqTree

JqTree is a jQuery widget for displaying a tree structure in html
It supports json data, loading via ajax and drag-and-drop.

Download jqTree

Introduction

JqTree is a jQuery widget for displaying a tree structure in html. It supports json data, loading via ajax and drag-and-drop.

Bower version

Features

  • Create a tree from JSON data
  • Load data using ajax
  • Drag and drop
  • Saves the state
  • Keyboard support
  • Lazy loading
  • Works on ie8+, firefox 3.6+, chrome and safari
  • Written in Coffeescript

The project is hosted on github, has a test suite.

Demo

var data = [
    {
        label: 'node1', id: 1,
        children: [
            { label: 'child1', id: 2 },
            { label: 'child2', id: 3 }
        ]
    },
    {
        label: 'node2', id: 4,
        children: [
            { label: 'child3', id: 5 }
        ]
    }
];
$('#tree1').tree({
    data: data,
    autoOpen: true,
    dragAndDrop: true
});

Requirements

Downloads

Tutorial

Include jQuery

<script src="jquery.min.js"></script>

Include tree.jquery.js:

<script src="tree.jquery.js"></script>

Include jqtree.css:

<link rel="stylesheet" href="jqtree.css">

Optionally, for saveState include jquery-cookie:

<script src="jquery.cookie.js"></script>

Create a div.

<div id="tree1"></div>

Create tree data.

var data = [
    {
        label: 'node1',
        children: [
            { label: 'child1' },
            { label: 'child2' }
        ]
    },
    {
        label: 'node2',
        children: [
            { label: 'child3' }
        ]
    }
];

Create tree widget.

$(function() {
    $('#tree1').tree({
        data: data
    });
});

Alternatively, get the data from the server.

$.getJSON(
    '/some_url/',
    function(data) {
        $('#tree1').tree({
            data: data
        });
    }
);

Examples

Changelog

0.22 (september 25 2014)
  • Issue 291: Dragging Item - do not open node if you don’t stay over it (thanks to Roman Klos)
  • Issue 300: Toggle function should get default slide value from options (thanks to Tazle)
  • Issue 303: Correctly set selected_node parameter in query string
  • Issue 315: Fix for issue when moving node over closed folder (thanks to terrybr)
  • Issue 320: Fixed error in drag and drop (thanks to Jerry Wu)
0.21 (june 7 2014)
  • Issue 263: Improve styling of toggle button
  • Issue 266: Make it possible to use html for toggle buttons
  • Issue 262: updateNode on first level makes node disappear (thanks to Miloš Đekić)
  • Issue 260: Exempt ‘select’ elements from keyboard navigation (thanks to Eli Flanagan)
  • Issue 270: Fixed error ‘selected_single_node is not defined’ (thanks to Bryan Smith)
  • Issue 279: .jqtree-moving removed when loading subtree (thanks to Marc-Stefan Cassola)
  • Issue 280: CSS3 Circle and style optimization (thanks to Marc-Stefan Cassola)
  • Issue 283: Added function getNodesByProperty (thanks to Cedrik Vanderhaegen)
  • Issue 292: Save state if multiple nodes are selected (thanks to MykhailoP)
  • Issue 294: Handle click on input element in tree (thanks to Naeco33)
0.20 (march 9 2014)
  • Issue 235: Added setOption function
  • Issue 241: Prevent duplicate event call after re-initalization
  • Issue 246: Check if folder must be opened while moving node (thanks to Dave Gardner)
  • Issue 247: Improve performance of updateNode (thanks to Gordon Woodhull)
  • Issue 250: Improve performance of creating dom elements (thanks to Carlos Scheidegger)
  • Issue 252: BorderDropHint has wrong height for border-box box-sizing (thanks to simshaun)
  • Issue 253: Added reload function
  • Issue 256: Toggler button is underlined
  • Issue 257: Make it possible to open a lazily loaded folder using the keyboard
  • Issue 258: Correctly unselect children if a node is reloaded
0.19 (december 8 2013)
  • Issue 225: Fixes TypeError when removing nodes without ids that aren’t selected (thanks to Marcus McCurdy)
  • Issue 222: scrollToNode does not consider direct parent
  • Issue 228: add property click_event to tree.click and tree.dblclick events (thanks to Gordon Woodhull)
  • Issue 78: Added option openFolderDelay: the delay for opening a folder during drag-and-drop (thanks to Jason Diamond)
0.18 (september 17 2013)
  • Issue 132: Skip keyboard handling if focus is on input element (thanks to Bingeling)
  • Issue 179 and 180: Added dataFilter option to filter the returned data from jQuery.ajax (thanks to Cheton Wu and Tony Dilger)
  • Issue 184: If the node id is 0, the id mapping is incorrect (thanks to Ika Wu)
  • Issue 190: The function selectNode should not toggle (thanks to Gordon Woodhull)
  • Issue 192: Added keyboardSupport option (thanks to Ika Wu)
  • Issue 181: Added tree.dblclick event (thanks to eskaigualker)
  • Issue 196: localStorage doesn’t work in Safari private browsing (thanks to thebagg)
  • Issue 203: Adding deselected_node attribute to event object of tree.select event (thanks to tedtoer)
0.17 (july 14 2013)
  • Issue 132: Added keyboard support
  • Issue 154: Calling loadDataFromUrl should not trigger tree.init event (thanks to Davide Bellini)
  • Issue 158: Index not updated on updateNode (thanks to Sam Mousa)
  • Issue 159: Cannot reselect node after unselecting it (thanks to Comanche)
  • Issue 162: Added getPreviousSibling and getNextSibling functions (thanks to Dimaninc)
  • Issue 169: Added touch support (thanks to Comanche)
  • Issue 171: Added functions getState and setState
  • Issue 175: Make it possible to install jqTree using bower (thanks to Adam Miskiewicz)
0.16 (may 17 2013)
  • Issue 62: Added functions for multiple select
  • Issue 125: Add option for overriding TRIANGLE_RIGHT and TRIANGLE_DOWN (thanks to Sam D)
  • Issue 126: Event tree.open event fires after first tree.select on top level node
  • Issue 129: Allow native context menu to be display (thanks to Charles Bourasseau)
  • Issue 130: Selectable not implemented (thanks to Sam D)
  • Issue 133: loadDataFromUrl doesn’t work when only parent_node and callback are passed in (thanks to Simone Deponti)
  • Issue 134: selectNode from inside tree.init breaks on loadData (thanks to Sam D)
  • Issue 145: Auto-open nodes with drag n drop when drag not enabled for that node (thanks to Daniel Powell)
  • Issue 146: Added function scrollToNode (thanks to Davide Bellini)
0.15 (march 16 2013)
  • Issue 100: Clicking on the jqtree-element element will trigger click event
  • Issue 102: Add original event to tree.move event
  • Issue 103: Added getLevel function to Node class
  • Issue 104: The addNodeBefore method must return the new node
  • Issue 105: Added nodeClass option
  • Issue 112: Fix call to iterate in removeNode (thanks to Ingemar Ådahl)
  • Issue 113: Added onLoadFailed option (thanks to Shuhei Kondo)
  • Issue 118: Deselect a node when click and already selected
  • Issue 119: Make it easier to reload a subtree
  • Issue 121: Unselect node if it’s reloaded by loadDataFromUrl
0.14 (december 2 2012)
Api changes
  • Removed parameter must_open_parents from function selectNode.
  • Changed slide parameter in functions openNode and closeNode.
Issues
  • Issue 80: Support more options for loading data from the server. E.g. the ‘post’ method (thanks to Rodrigo Rosenfeld Rosas)
  • Issue 81: getSelectedNode must return false if node is removed
  • Issue 82: Autoscroll for drag-and-drop
  • Issue 84: Fix correct type param in $.ajax() (thanks to Rodrigo Rosenfeld Rosas)
  • Issue 85: Option to turn slide animation on or off
  • Issue 86: The openNode function must automatically open parents
  • Issue 87: Remove the must_open_parents parameter from the selectNode function
  • Issue 88: selectNode must also work if selectable option is false
  • Issue 89: Clicking in title with img or em does not work
  • Issue 96: Added jqtree_common class to avoid css clashes (thanks to Yaniv Iny)
0.13 (october 10 2012)
  • Issue 54: Added tree.select event
  • Issue 63: Fixed contextmenu event
  • Issue 67: Use unicode characters for triangle buttons (thanks to Younès)
  • Issue 70: Load data from the server using the loadData function
  • Issue 78: Drag and drop is trigger happy
0.12 (august 14 2012)
  • Issue 46: Added tree.refresh event
  • Issue 47: Function ‘selectNode’ must properly open the parent nodes
  • Issue 49: Make sure that widget functions can be called in the ‘tree.init’ event
  • Issue 50: Add namespace to css classes
  • Issue 51: closeNode to collapse tree doesn’t work
  • Issue 55: Load-on-demand from the server
  • Issue 58: Added updateNode function
  • Issue 59: Added moveNode function
  • Issue 60: Use native JSON.stringify function
0.11 (july 8 2012)
  • Autoescape text
  • Added autoEscape option
  • Issue 33: appendNode does not correctly refresh the tree
  • Issue 34: unset internal pointer to previously selected node on DOM deselect
  • Issue 38: Correctly check if browser has support for localstorage
  • Issue 41: Open nodes are not displayed correctly in ie7
0.10 (june 10 2012)
  • Optimized getNodeById
  • Issue #18 and #26: Made comparison in getNodeById less strict
  • Added function prependNode
  • Added ‘data-url’ option
  • Added removeNode function
  • Issue #24: Tree with jquery ui Dialog: expand causes resize and move problem
  • Added Travis ci support
  • Added addNodeAfter, addNodeBefore and addParentNode
  • Renamed icons.png to jqtree-icons.png
  • selectNode with empty node deselects the current node
0.9 (may 9 2012)
  • Issue 15: ‘tree.open’ event is not triggered when dragging nodes
  • Issue 18: Allow moveNode to be canceled through ev.preventDefault()
  • Use sprite for images
  • Added function closeNode
  • Added support for localstorage
  • Implemented alternative data format
0.8 (april 18 2012)
  • Replace jquery.ui widget with SimpleWidget
  • Added ‘previous_parent’ to ‘tree.move’ event
  • Add posibility to load subtree
  • Added ‘tree.open’ and ‘tree.close’ events

Tree options

autoEscape

Determine if text is autoescaped. The default is true.

autoOpen

Open nodes initially.

  • true: open all nodes.
  • false (default): do nothing
  • n: open n levels

Open all nodes initially:

$('#tree1').tree({
    data: data,
    autoOpen: true
});

Open first level nodes:

$('#tree1').tree({
    data: data,
    autoOpen: 0
});

closedIcon

A character or symbol to display on closed nodes. The default is ‘&#x25ba;’ (►)

$('#tree1').tree({
    closedIcon: '+'
});

data

Define the contents of the tree. The data is a nested array of objects. This option is required.

It looks like this:

var data = [
    {
        label: 'node1',
        children: [
            { label: 'child1' },
            { label: 'child2' }
        ]
    },
    {
        label: 'node2',
        children: [
            { label: 'child3' }
        ]
    }
];
$('#tree1').tree({data: data});
  • label: label of a node (required)
  • children: array of child nodes (optional)

You can also include other data in the objects. You can later access this data.

For example, to add an id:

{
    label: 'node1',
    id: 1
}

dataFilter

Process the tree data from the server.

$('#tree1').tree({
    url: '/my/data/',
    dataFilter: function(data) {
        // Example:
        // the server puts the tree data in 'my_tree_data'
        return data['my_tree_data'];
    }
});

dataUrl

Load the node data from this url.

$('#tree1').tree({
   dataUrl: '/example_data.json' 
});

You can also set the data-url attribute on the dom element:

<div id="tree1" data-url="/example_data.json"></div>
<script>
    $('#tree1').tree();
</script>

dragAndDrop

Turn on dragging and dropping of nodes.

  • true: turn on drag and drop
  • false (default): do not allow drag and drop

Example: turn on drag and drop.

$('#tree1').tree({
    data: data,
    dragAndDrop: true
});

keyboardSupport

Enable or disable keyboard support. Default is enabled.

Example: disable keyboard support.

$('#tree1').tree({
    keyboardSupport: false
});

onCanMove

You can override this function to determine if a node can be moved.

$('#tree1').tree({
    data: data,
    dragAndDrop: true,
    onCanMove: function(node) {
        if (! node.parent.parent) {
            // Example: Cannot move root node
            return false;
        }
        else {
            return true;
        }
    }
});

onCanMoveTo

You can override this function to determine if a node can be moved to a certain position.

$('#tree1').tree({
    data: data,
    dragAndDrop: true,
    onCanMoveTo: function(moved_node, target_node, position) {
        if (target_node.is_menu) {
            // Example: can move inside menu, not before or after
            return (position == 'inside');
        }
        else {
            return true;
        }
    }
});

onCanSelectNode

You can set a function to override if a node can be selected. The function gets a node as parameter, and must return true or false.

For this to work, the option ‘selectable’ must be ‘true’.

// Example: nodes with children cannot be selected
$('#tree1').tree({
    data: data,
    selectable: true
    onCanSelectNode: function(node) {
        if (node.children.length == 0) {
            // Nodes without children can be selected
            return true;
        }
        else {
            // Nodes with children cannot be selected
            return false;
        }
    }
});

onCreateLi

The function is called for each created node. You can use this to define extra html.

$('#tree1).tree({
    data: data,
    onCreateLi: function(node, $li) {
        // Add 'icon' span before title
        $li.find('.jqtree-title').before('<span class="icon"></span>');
    }
});

onIsMoveHandle

You can override this function to determine if a dom element can be used to move a node.

$('#tree1').tree({
    data: data,
    onIsMoveHandle: function($element) {
        // Only dom elements with 'jqtree-title' class can be used
        // as move handle.
        return ($element.is('.jqtree-title'));
    }
});

onLoadFailed

When loading the data by ajax fails, then the option onLoadFailed is called.

$('#tree1').tree({
    url: '/my/data/',
    onLoadFailed: function(response) {
        //
    }
});

openedIcon

A character or symbol to display on opened nodes. The default is ‘&#x25bc;’ (▼)

$('#tree1').tree({
    openedIcon: '-'
});

openFolderDelay

Set the delay for opening a folder during drag-and-drop. The delay is in milliseconds. The default is 500 ms.

$('#tree1').tree({
    url: '/my/data/',
    openFolderDelay: 1000
});

saveState

Save and restore the state of the tree automatically. Saves in a cookie which nodes are opened and selected.

The state is saved in localstorage. In browsers that do not support localstorage, the state is saved in a cookie. For this to work, please include jquery-cookie.

For this to work, you should give each node in the tree data an id field:

{
    label: 'node1',
    id: 123,
    childen: [
        label: 'child1',
        id: 124
    ]
}
  • true: save and restore state in a cookie
  • false (default): do nothing
  • string: save state and use this name to store in a cookie
$('#tree1').tree({
    data: data,
    saveState: true
});

Example: save state in key ‘tree1’:

$('#tree1').tree({
    data: data,
    saveState: 'tree1'
});

selectable

Turn on selection of nodes.

  • true (default): turn on selection of nodes
  • false: turn off selection of nodes

Example: turn off selection of nodes.

$('#tree1').tree({
    data: data,
    selectable: false
});

slide

Turn slide animation on or off. Default is true.

$('#tree1').tree({
    slide: false
});

useContextMenu

Bind the context menu event (true/false).

true (default)

A right mouse-click will trigger a tree.contextmenu event. This overrides the native contextmenu of the browser.

false

A right mouse-click will trigger the native contextmenu of the browser.

Functions

addNodeAfter

function addNodeAfter(new_node_info, existing_node);

Add a new node after this existing node.

var node1 = $('#tree1', 'getNodeByName', 'node1');
$('#tree1').tree(
    'addNodeAfter',
    {
        label: 'new_node',
        id: 456
    },
    node1
);

addNodeBefore

function addNodeBefore(new_node_info, existing_node);

Add a new node before this existing node.

appendNode

function appendNode(new_node_info, parent_node);

Add a node to this parent node. If parent_node< is empty, then the new node becomes a root node.

var parent_node = $tree.tree('getNodeById', 123);

$tree.tree(
    'appendNode',
    {
        label: 'new_node',
        id: 456
    },
    parent_node
);

To add a root node, leave parent_node empty:

$tree.tree(
    'appendNode',
    {
        label: 'new_node',
        id: 456
    }
);

closeNode

function closeNode(node);

function closeNode(node, slide);

Close this node. The node must have child nodes.

Parameter slide: close the node using a slide animation (default is true).

var node = $tree.tree('getNodeById', 123);
$tree.tree('closeNode', node);

To close the node without the slide animation, call with slide parameter is false.

$tree.tree('closeNode', node, false);

getNodeById

function getNodeById(id);

Get a tree node by node-id. This assumes that you have given the nodes in the data a unique id.

var $tree = $('#tree1');
var data = [
    { id: 10, name: 'n1' },
    { id: 11, name: 'n2' }
];

$tree.tree({
    data: data
});
var node = $tree.tree('getNodeById', 10);

getSelectedNode

Get the selected node. Returns the row data or false.

var node = $tree.tree('getSelectedNode');

getState

Get the state of tree: which nodes are open and which one is selected?

Returns a javascript object that contains the ids of open nodes and selected nodes:

{
    open_nodes: [1, 2, 3],
    selected_node: [4, 5, 6]
}

If you want to use this function, then your tree data should include an id property for each node.

You can use this function in combination with setState to save and restore the tree state.

getTree

function getTree();

Get the root node of the tree.

loadData

function loadData(data);

function loadData(data, parent_node);

Load data in the tree. The data is array of nodes.

You can replace the whole tree or you can load a subtree.

// Assuming the tree exists
var new_data = [
    {
        label: 'node1',
        children: [
            { label: 'child1' },
            { label: 'child2' }
        ]
    },
    {
        label: 'node2',
        children: [
            { label: 'child3' }
        ]
    }
];
$('#tree1').tree('loadData', new_data);

Load a subtree:

// Get node by id (this assumes that the nodes have an id)
var node = $('#tree1').tree('getNodeById', 100);

// Add new nodes
var data = [
    { label: 'new node' },
    { label: 'another new node' }
];
$('#tree1').tree('loadData', data, node);

loadDataFromUrl

function loadDataFromUrl(url);

function loadDataFromUrl(url, parent_node);

function loadDataFromUrl(parent_node);

Load data in the tree from an url using ajax. You can replace the whole tree or you can load a subtree.

$('#tree1').tree('loadDataFromUrl', '/category/tree/');

Load a subtree:

var node = $('#tree1').tree('getNodeById', 123);
$('#tree1').tree('loadDataFromUrl', '/category/tree/123', node);

You can also omit the url. In this case jqTree will generate a url for you. This is very useful if you use the load-on-demand feature:

var $tree = $('#tree1');

$tree.tree({
    dataUrl: '/my_data/'
});

var node = $tree.tree('getNodeById', 456);

// jqTree will load data from /my_data/?node=456
$tree.tree('loadDataFromUrl', node);

You can also add an on_finished callback parameter that will be called when the data is loaded:

function loadDataFromUrl(url, parent_node, on_finished);

function loadDataFromUrl(parent_node, on_finished);

$('#tree1').tree(
    'loadDataFromUrl',
    '/category/tree/123',
    null,
    function() {
        alert('data is loaded');
    }
);

moveNode

function moveNode(node, target_node, position);

Move a node. Position can be ‘before’, ‘after’ or ‘inside’.

var node = $tree.tree('getNodeById', 1);
var target_node = $tree.tree('getNodeById', 2);

$tree.tree('moveNode', node, target_node, 'after');

openNode

function openNode(node);

function openNode(node, slide);

Open this node. The node must have child nodes.

Parameter slide: open the node using a slide animation (default is true).

// create tree
var $tree = $('#tree1');
$tree.tree({
    data: data
});

var node = $tree.tree('getNodeById', 123);
$tree.tree('openNode', node);

To open the node without the slide animation, call with slide parameter is false.

$tree.tree('openNode', node, false);

addParentNode

function addParentNode(new_node_info, existing_node);

Add a new node as parent of this existing node.

var node1 = $('#tree1', 'getNodeByName', 'node1');
$('#tree1').tree(
    'addParentNode',
    {
        label: 'new_parent',
        id: 456
    },
    node1
);

reload

function reload();

Reload data.

$('#tree1').tree('reload');

removeNode

function removeNode(node);

Remove node from the tree.

$('#tree1').tree('removeNode', node);

selectNode

function selectNode(node);

function selectNode(null);

Select this node.

You can deselect the current node by calling selectNode(null).

// create tree
var $tree = $('#tree1');
$tree.tree({
    data: data,
    selectable: true
});

var node = $tree.tree('getNodeById', 123);
$tree.tree('selectNode', node);

scrollToNode

function scrollToNode(node);

Scroll to this node. This is useful if the tree is in a container div and is scrollable.

var node = $tree.tree('getNodeById', 1);
$tree.tree('scrollToNode', node);

setOption

function setOption(option, value);

Set a tree option. These are the same options that you can set when creating the tree.

$('#tree1').tree('setOption', 'keyboardSupport', false);

setState

Set the state of the tree: which nodes are open and which one is selected?

See getState for more information.

toggle

function toggle(node);

Open or close the tree node.

toJson

function toJson();

Get the tree data as json.

// Assuming the tree exists
$('#tree1').tree('toJson');

updateNode

function updateNode(node, label);

function updateNode(node, data);

Update the title of a node. You can also update the data.

Update the label:

var node = $tree.tree('getNodeById', 123);

$tree.tree('updateNode', node, 'new label');

Update the data (including the label)

var node = $tree.tree('getNodeById', 123);

$tree.tree(
    'updateNode',
    node,
    {
        label: 'new label',
        other_property: 'abc'
    }
);

Events

tree.click

Triggered when a tree node is clicked. The event contains the following properties:

  • node: the node that is clicked on
  • click_event: the original click event
// create tree
$('#tree1').tree({
    data: data
});

// bind 'tree.click' event
$('#tree1').bind(
    'tree.click',
    function(event) {
        // The clicked node is 'event.node'
        var node = event.node;
        alert(node.name);
    }
);

The default action is to select the node. You can prevent the selection by calling preventDefault:

$('#tree1').bind(
    'tree.click',
    function(event) {
        event.preventDefault();
    }
);

tree.close

Called when a node is closed.

$('#tree1').bind(
    'tree.close',
    function(e) {
        console.log(e.node);
    }
);

tree.contextmenu

Triggered when the user right-clicks a tree node. The event contains the following properties:

  • node: the node that is clicked on
  • click_event: the original click event
// bind 'tree.contextmenu' event
$('#tree1').bind(
    'tree.contextmenu',
    function(event) {
        // The clicked node is 'event.node'
        var node = event.node;
        alert(node.name);
    }
);

tree.dblclick

The tree.dblclick is fired when a tree node is double-clicked. The event contains the following properties:

  • node: the node that is clicked on
  • click_event: the original click event
$('#tree1').bind(
    'tree.dblclick',
    function(event) {
        // event.node is the clicked node
        console.log(event.node);
    }
);

tree.init

Called when the tree is initialized. This is particularly useful when the data is loaded from the server.

$('#tree1').bind(
    'tree.init',
    function() {
        // initializing code
    }
);

tree.move

Triggered when the user moves a node.

Event.move_info contains:

  • moved_node
  • target_node
  • position: (before, after or inside)
  • previous_parent
$('#tree1').tree({
    data: data,
    dragAndDrop: true
});

$('#tree1').bind(
    'tree.move',
    function(event) {
        console.log('moved_node', event.move_info.moved_node);
        console.log('target_node', event.move_info.target_node);
        console.log('position', event.move_info.position);
        console.log('previous_parent', event.move_info.previous_parent);
    }
);

You can prevent the move by calling event.preventDefault()

$('#tree1').bind(
    'tree.move',
    function(event) {
        event.preventDefault();
    }
);

You can later call event.move_info.move_info.do_move() to move the node. This way you can ask the user before moving the node:

$('#tree1').bind(
    'tree.move',
    function(event) {
        event.preventDefault();

        if (confirm('Really move?')) {
            event.move_info.do_move();
        }
    }
);

Note that if you want to serialise the tree, for example to POST back to a server, you need to let tree complete the move first:

$('#tree1').bind(
    'tree.move',
    function(event)
    {
        event.preventDefault();
        // do the move first, and _then_ POST back.
        event.move_info.do_move();
        $.post('your_url', {tree: $(this).tree('toJson')});
    }
);

tree.open

Called when a node is opened.

$('#tree1').bind(
    'tree.open',
    function(e) {
        console.log(e.node);
    }
);

tree.select

Triggered when a tree node is selected or deselected.

If a node is selected, then event.node contains the selected node.

If a node is deselected, then the event.node property is null.

$('#tree1').bind(
    'tree.select',
    function(event) {
        if (event.node) {
            // node was selected
            var node = event.node;
            alert(node.name);
        }
        else {
            // event.node is null
            // a node was deselected
            // e.previous_node contains the deselected node
        }
    }
);

Multiple selection

Jqtree has some functions that can help you to implement multiple selection. See Example 8 - multiple select.

In order for multiple selection to work, you must give the nodes an id.

addToSelection

Add this node to the selection

var node = $('#tree1').tree('getNodeById', 123);
$('#tree1').tree('addToSelection', node);

getSelectedNodes

Return a list of selected nodes.

var nodes = $('#tree1').tree('getSelectedNodes');

isNodeSelected

Return if this node is selected.

var node = $('#tree1').tree('getNodeById', 123);
var is_selected = $('#tree1').tree('isNodeSelected', node);

removeFromSelection

Remove this node from the selection.

var node = $('#tree1').tree('getNodeById', 123);
$('#tree1').tree('removeFromSelection', node);

Node functions

You can access a node using for example getNodeById function:

var node = $('#tree1').tree('getNodeById', 123);

The Node object has the following properties and functions:

children

You can access the children of a node using the children property.

for (var i=0; i < node.children.length; i++) {
    var child = node.children[i];
}

getData

Get the subtree of this node.

var data = node.getData();

getLevel

Get the level of a node. The level is distance of a node to the root node.

var node = $('#tree1').tree('getNodeById', 123);

// result is e.g. 2
var level = node.getLevel();

getNextSibling

Get the next sibling of this node. Returns a node or null.

var node = node.getNextSibling();

getPreviousSibling

Get the previous sibling of this node. Returns a node or null.

var node = node.getPreviousSibling();

parent

You can access the parent of a node using the parent property.

var parent_node = node.parent;