Saturday, September 21, 2013

Tree View using Knockout.JS

Recently I tried out various Javascript frameworks, among them Knockout.js. What I found most impressive was how easy it was to build a tree view using Knockout. All you have to do is create a template that calls itself for rendering the child nodes:
<script type="text/html" id="tree-node">
    <li>
        <i data-bind="css: {'icon-collapse-alt': expanded, 'icon-expand-alt': collapsed}, click: toggle"></i>
        <span data-bind="text: name, click: $root.selected"></span>

        <div data-bind="if: expanded">
            <ul data-bind="template: {name: 'tree-node', foreach: children}"></ul>
        </div>
    </li>
</script>
Then you place the tree view in your HTML like this:
<ul data-bind="template: {name: 'tree-node', data: root}"></ul>
And of course you need a view model for the tree:

  function TreeNode(values) {
      var self = this;
      ko.mapping.fromJS(values, { children: { create: createNode }}, this);
      this.expanded = ko.observable(false);
      this.collapsed = ko.computed(function() {
      return !self.expanded();
    })
  }
  
  TreeNode.prototype.toggle = function () {
      this.expanded(!this.expanded());
  };
  
  function createNode(options) {
      return new TreeNode(options.data);
  }
  
  var root = new TreeNode({ id: "1", name: "Root", children: [
      { id: "1.1", name: "Node 1", children: [
          {id: "1.1.1", name: "Node 1.1", children: []},
          {id: "1.1.2", name: "Node 1.2", children: []}
      ]},
      { id: "1.2", name: "Node 2", children: []}
  ]});
  
  var viewModel = {
      root: root,
      selected: ko.observable()
  };
  
  ko.applyBindings(viewModel, $('html')[0]);
You can try this example live in this Plunkr.