Get to know the Tree!

Tree is a control provided by Fuel UX. It is best used for hierarchical data such as a collection of branching folders and their contained items.

We will be using it to make this tree

This tutorial introduces the basic use of tree.

Tree diagram

Step 1Set up the template

In this tutorial, we reference Fuel UX and its dependencies from their CDNs. See the Getting Started page in the documentation for more info.

Create an HTML page. Paste the following for this demo, so it references CSS in the <head> and the JavaScript files Fuel UX, Bootstrap, and jQuery just above </body>.

<!DOCTYPE html>
<html lang="en" class="fuelux">
  <head>
    <meta charset="utf-8">
    <title>Fuel UX Test</title>
    <link href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css" rel="stylesheet"/>
    <link href="http://www.fuelcdn.com/fuelux/3.7.3/css/fuelux.min.css" rel="stylesheet"/>
  </head>
  <body>

    <script src="http://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <script src="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js"></script>
    <script src="http://www.fuelcdn.com/fuelux/3.7.3/js/fuelux.min.js"></script>
  </body>
</html>

Open the page on your server or with these dependencies set up in a CodePen. If you view the output, you should see a blank page. If you open the browser console, there should be no errors.

Step 2Add tree markup

Fuel UX binds to existing markup on the page (just like Bootstrap). Start by placing the tree markup inside of the body tags:

The tree control is an empty ul container until data is loaded into the tree via the dataSource method. Data can only be loaded one folder at a time.

The tree uses the markup within data-template="treebranch" and data-template="treeitem" at the time of initialization to create it's children.

This example uses the folders selectable option. The recommended markup differs if you do not want folders to be selectable. The main difference is whether the caret is located within tree-branch-name or not.

The nodes of the tree are very flexible. Based on your data, you can have a virtually unlimited variety of HTML attributes on your nodes. These attributes get added to the tree-branch and tree-item elements.

<ul id="myTree" class="tree tree-folder-select" role="tree" id="myTree">
  <li class="tree-branch hide" data-template="treebranch" role="treeitem" aria-expanded="false">
    <div class="tree-branch-header">
      <button class="glyphicon icon-caret glyphicon-play"><span class="sr-only">Open</span></button>
      <button class="tree-branch-name">
        <span class="glyphicon icon-folder glyphicon-folder-close"></span>
        <span class="tree-label"></span>
      </button>
    </div>
    <ul class="tree-branch-children" role="group"></ul>
    <div class="tree-loader" role="alert">Loading...</div>
  </li>
  <li class="tree-item hide" data-template="treeitem" role="treeitem">
    <button class="tree-item-name">
      <span class="glyphicon icon-item fueluxicon-bullet"></span>
      <span class="tree-label"></span>
    </button>
  </li>
</ul>

Step 3Create a static data function:

When the tree needs to load the children of a recently opened folder, it will call your dataSource function and pass in two arguments:

  • openedParentData - an object containing information on the folder being opened
  • callback - a function called when the data is ready for rendering

There are only two required properties within the data object passed to the callback: text which is a string and type can either be folder or item. However, you can have any number of attributes on your nodes by using the attr object.

Let's start by creating the function staticDataSource to handle this. Place this function within a <script> before you initialize your tree. The tree still hasn't been initialized, so you will not see any changes yet. The following uses the names of works by M. C. Escher and will add the same children each time.

function staticDataSource(openedParentData, callback) {
  childNodesArray = [
    { "name": "Ascending and Descending", "type": "folder" },
    { "name": "Sky and Water I", "type": "item" },
    { "name": "Drawing Hands", "type": "folder" },
    { "name": "waterfall", "type": "item" },
    { "name": "Belvedere", "type": "folder" },
    { "name": "Relativity", "type": "item" },
    { "name": "House of Stairs", "type": "folder" },
    { "name": "Convex and Concave", "type": "item" }
  ];

  callback({
    data: childNodesArray
  });
}

Step 4Initialize the tree

Initialize the tree, passing in the staticDataSource you just created as the dataSource:

$(function() {
   $('#myTree').tree({
      dataSource: staticDataSource,
      multiSelect: false,
      folderSelect: true
    });
});

Here is this example on CodePen

AsideExample with an API

If you wanted to change the data providing function to fetch the dataset rows from an API and calculate the datasource properties from the results, you could do something like this (we won't be using this for our tutorial though, since it requires a specific response from your server and won't work locally.):

function dynamicDataSource(openedParentData, callback) {
  var childNodesArray = [];

  // call API, posting options
  $.ajax({
    'type': 'post',
    'url': '/tree/data',
    'data': openedParentData  // first call with be an empty object
  })
  .done(function(data) {
    // configure datasource
    var childObjectsArray = data;

    // pass an array with the key 'data' back to the tree
    // [ {'name': [string], 'type': [string], 'attr': [object] } ]
    callback({
      data: childNodesArray
    });

  });
}

Let's return to the staticDataSource function and add custom attributes.

Step 5Add custom attrbutes

Additional HTML attributes can be added to the attr object. The following are reserved:

  • attr.id element ID
  • cssClassclass of the tree node (please remember the style cascade)
  • attr.data-icon custom icon class
  • attr.hasChildrenwhether to hide the caret if there are no child nodes.

In the following code, data-icon has been added to the attr to use custom icons. This will apply the specified class to the icon span before the text label in folders and items.

function staticDataSource(parentData, callback) {
  // includes rebeccapurple styling

  childNodesArray = [
    {
      "name": "Ascending and Descending",
      "type": "folder",
      "attr": {
        "id": "ascending-and-descending"
      }
    },
    {
      "name": "Sky and Water I",
      "type": "item",
      "attr": {
        "id": "sky-and-water-i",
        "data-icon": "glyphicon glyphicon-file",
        "style": "color: rebeccapurple;"
      }
    },
    {
      "name": "Drawing Hands",
      "type": "folder",
      "attr": {
        "id": "drawing-hands"
      }
    },
    {
      "name": "Waterfall",
      "type": "item",
      "attr": {
        "id": "waterfall",
        "data-icon": "glyphicon glyphicon-cloud",
        "style": "color: rebeccapurple;"
      }
    },
    {
      "name": "Belvedere",
      "type": "folder",
      "attr": {
        "id": "belvedere"
      }
    },
    {
      "name": "Relativity",
      "type": "item",
      "attr": {
        "id": "relativity",
        "data-icon": "glyphicon glyphicon-picture",
        "style": "color: rebeccapurple;"
      }
    },
    {
      "name": "House of Stairs",
      "type": "folder",
      "attr": {
        "id": "house-of-stairs"
      }
    },
    {
      "name": "Convex and Concave",
      "type": "item",
      "attr": {
        "id": "convex-and-concave",
        "data-icon": "glyphicon glyphicon-tags",
        "style": "color: rebeccapurple;"
      }
    }
  ];

  callback({
    data: childNodesArray
  });
}

Step 6Interacting with events

Your application will want to interact with the tree by listening for events. Here are an example of a few ways. View the Tree Events table for more ways to interact.

$('#myTree').on('deselected.fu.tree selected.fu.tree', function(event) {
  // insert JSON text of selected items after tree
  $('#myTree').after('SELECTED ITEMS: ' + JSON.stringify( $('#myTree').tree('selectedItems') ) + '<br>' );
});

$('#myTree').on('disclosedFolder.fu.tree closed.fu.tree', function(event, parentData) {
  // insert JSON text of selected items after tree
  $('#myTree').after('OPENED/CLOSED FOLDER DATA: ' + JSON.stringify( parentData ) + ' ' );
});

Here is this example on CodePen.

Tree with custom attributes

That's all folks!

Now that you've created a simple tree, we'd love to get feedback on Twitter about this tutorial or any of the other 15 Fuel UX controls. We love fixing issues and receiving pull requests on Github. Open source for-the-win!

Sincerely yours,
Stephen
and the Fuel UX team

Github Twitter