jqTree

JqTree is a tree widget.

Features

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


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

Requirements

Downloads

Tutorial

Examples

Changelog

0.15 (march 16 2013)
0.14 (december 2 2012)
Api changes
Issues
0.13 (october 10 2012)
0.12 (august 14 2012)
0.11 (july 8 2012)
0.10 (june 10 2012)
0.9 (may 9 2012)
0.8 (april 18 2012)

Tree options

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

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
}
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>
autoOpen

Open nodes initially.

Open all nodes initially:


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

Open first level nodes:


$('#tree1').tree({
    data: data,
    autoOpen: 0
});
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
    ]
}

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

Example: save state in key 'tree1':


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

Turn on dragging and dropping of nodes.

Example: turn on drag and drop.


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

Turn on selection of nodes.

Example: turn on selection of nodes.


$('#tree1').tree({
    data: data,
    selectable: 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'));
    }
});
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;
        }
    }
});
autoEscape

Determine if text is autoescaped. The default is true.

slide

Turn slide animation on or off. Default is true.


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

Functions

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').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');
    }
);
toJson

function toJson();
Get the tree data as json.


// Assuming the tree exists
$('#tree1').tree('toJson');
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);
selectNode

function selectNode(node);

Select this node.


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

var node = $tree.tree('getNodeById', 123);
$tree.tree('selectNode', node);
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);
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);
getSelectedNode

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


var node = $tree.tree('getSelectedNode');
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.

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

function removeNode(node);

Remove node from the tree.


$('#tree1').tree('removeNode', 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
    }
);
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'
    }
);
moveNode

function moveNode(node, target_node, position);

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


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

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

function toggle(node);
function toggle(node, slide);

Open or close a node.
Parameter slide: a slide animation (default is true).


var node = $tree.tree('getNodeBydId', 1);
$tree.tree('toggle', node);

Events

tree.click

Triggered when a tree node is clicked.


// 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);
    }
);
tree.select

Triggered when a tree node is selected.


$('#tree1').bind(
    'tree.select',
    function(event) {
        var node = event.node;
        alert(node.name);
    }
);
tree.contextmenu

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


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

Triggered when the user moves a node.

Event.move_info contains:


$('#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.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.open

Called when a node is opened.


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

Tree designed by Hernan D. Schlosman from The Noun Project