Skip to content
Martin Wendt edited this page Aug 25, 2020 · 6 revisions

How to handle nodes by type.

Assume a large tree of products that is organized by type:

Books
  +- Little Prince
  +- The Hobbit
Computers
  +- PC
  +- Mac

All book nodes should have a book-icon, while all computer nodes should have a computer icon. All nodes should also have icon tooltips.

This would require to define and transport the same data over and over again:

[
  {"title": "Books", "folder": true, "children": [
    {"title": "Little Prince", "icon": "ft-ico-book", "iconTooltip": "This is a book.", "price": 1.23},
    {"title": "The Hobbit", "icon": "ft-ico-book", "iconTooltip": "This is a book.", "price": 2.34}
  ]},
  {"title": "Computers", "folder": true, "children": [
    {"title": "PC", "icon": "ft-ico-computer", "iconTooltip": "This is a computer.", "price": 549.85},
    {"title": "Mac", "icon": "ft-ico-computer", "iconTooltip": "This is a computer.", "price": 789.00}
  ]}
]

Instead, we could use a simple pattern that allows to share data per node type.

Related properties:

  • New first-class property node.type
  • New first-class property tree.types
  • All events pass data.typeInfo (or {} if not defined)
  • TODO: support tree.types[node.type].extraClasses
  • TODO: should data.typeInfo.icon be evaluated automatically to set the icon without having to define the icon callback?
  • TODO: should we support hierarchical types? For example: books, books.english, and books.german. We need a use case for this, but at least '.' should be proposed as delimiter for our pattern.

Some next steps are started in the types2 branch.

Allow to define options by type name:

$("#tree").fancytree({
  // `types` is a tree option, that can be used to define shared data per node-type.
  // It should contain an object with one key per expected type.
  // We can pass it directly as fancytree option like this:
  types: {
    "book": {icon: "ft-ico-book", iconTooltip: "This is a book"},
    "computer": {icon: "ft-ico-computer", iconTooltip: "This is a computer"},
  },
  source: { url: "/my/web/service"},
  icon: function(event, data) {
    // data.typeInfo contains tree.types[node.type] (or {} if not found)
    // Here we will return the specific icon for that type, or `undefined` if
    // not type info is defined (in this case a default icon is displayed).
    return data.typeInfo.icon;
  },
  iconTooltip: function(event, data) {
     return data.typeInfo.iconTooltip;
  }
});

This pattern works especially well with dynamic options like checkbox, icon, iconTooltip, tooltip, unselectable, unselectableIgnore, unselectableStatus.

Sometimes it may be more convenient to get the shared types info from the server. The source JSON data can be a list of child nodes or an object with additional meta data. Here we use the latter format to pass type information as well:

{
  "children": [
    {"title": "Books", "folder": true, "children": [
      {"title": "Little Prince", "type": "book", "price": 1.23},
      {"title": "The Hobbit", "type": "book", "price": 2.34}
    ]},
    {"title": "Computers", "folder": true, "children": [
      {"title": "PC", "type": "computer", "price": 549.85},
      {"title": "Mac", "type": "computer", "price": 789.00}
    ]}
  ],
  "types": {
    "book": {"icon": "ft-ico-book", "iconTooltip": "This is a book"},
    "computer": {"icon": "ft-ico-computer", "iconTooltip": "This is a computer."}
  }
}

Note that sometimes things can even be more simplified by imposing conventions. For example if the icon class names follow a simple rule, we may omit the icon data altogether and derive it from the type:

$("#tree").fancytree({
  ...
  icon: function(event, data) {
    if( data.node.type ) {
      return "ft-ico-" + data.node.type;
    }
  },
});
Clone this wiki locally