<!doctype html> <html> <head> <title>Angular Tree</title> <script src="demo/jquery.2.0.3.js"></script> <script src="demo/angular.1.2.29.js"></script> <script src="demo/bootstrap.3.1.1.js"></script> <script src="demo/ui-bootstrap-tpls.0.11.2.js"></script> <script src="demo/prettify.1.0.1.js"></script> <link href="demo/bootstrap.3.1.1.css" rel="stylesheet" type="text/css"> <link href="demo/prettify-style.css" rel="stylesheet" type="text/css"> <script src="angular-tree-control.js"></script> <link rel="stylesheet" type="text/css" href="css/tree-control.css"> <link rel="stylesheet" type="text/css" href="css/tree-control-attribute.css"> <style> .header{padding-top: 50px; padding-bottom:50px; background-color: #444980;} .head-container{width: 1140px; margin:auto;} .header h1 {color: #fffffa; font-size: 60px} .header h2 {color: #fffffa; font-size: 24px; font-style: normal} .example-caption {color: #bbb; font-size: 12px} .docs-body{width: 1140px; margin: auto auto 50px; } .docs-footer{background-color: #F5F5F5; text-align: center; padding: 30px 0; border-top: #e5e5e5} .tab-pane{background-color: #f8f8f8; border-right: 1px solid #ccc;border-left: 1px solid #ccc;border-bottom: 1px solid #ccc; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px } .nav li.active a{background-color: #f8f8f8} pre.code {border:none; background-color: #f8f8f8; padding: 10px; margin: 0; font-family: Consolas, 'Liberation Mono', Courier, monospace;} .docs-sidenav { margin-top: 45px; margin-bottom: 0; } .docs-sidenav > li > a {display: block; font-size: 13px; font-weight: 500; color: #999; padding: 4px 20px;} .docs-sidenav > li.active > a {font-weight: 700; color: #563d7c; border-left: 2px solid #563d7c;padding-left: 18px;} .docs-sidenav > li > a:hover {background-color: transparent; color: #563d7c; border-left: 1px solid #563d7c;padding-left: 19px;} .type-hint-object {background:#999;} .type-hint-boolean {background:rgb(18, 131, 39);} .type-hint-number {background:rgb(189, 63, 66);} </style> </head> <body ng-app="example"> <a href="https://github.com/wix/angular-tree-control"><img style="position: absolute; top: 0; right: 0; border: 0;" src="https://camo.githubusercontent.com/652c5b9acfaddf3a9c326fa6bde407b87f7be0f4/68747470733a2f2f73332e616d617a6f6e6177732e636f6d2f6769746875622f726962626f6e732f666f726b6d655f72696768745f6f72616e67655f6666373630302e706e67" alt="Fork me on GitHub" data-canonical-src="https://s3.amazonaws.com/github/ribbons/forkme_right_orange_ff7600.png"></a> <div class="header"> <div class="head-container"> <h1>Angular Tree</h1> <h2>The AngularJS tree component</h2> </div> </div> <div class="row docs-body"> <div class="col-md-9"> <section id="classic" ng-controller="Classic"> <div class="page-header"> <h1>Basic Usage <small>(Classic style, default configuration)</small></h1> </div> <div class="row"> <div class="col-md-6 show-grid"> <div class="panel panel-default"> <div class="panel-body"> <div class="example-caption">EXAMPLE:</div> <div save-content="classic-html"> <treecontrol class="tree-classic" tree-model="treedata" on-selection="showSelected(node)"> label: {{node.label}} ({{node.id}}) </treecontrol> </div> </div> </div> </div> <div class="col-md-6"> <p>Classic style of the tree control, set using the class <code>tree-classic</code>.</p> <p>Click on the folder icons to open and close the tree nodes. Click on the node label to select a node in the tree. A Second click on the node label will unselect the node.</p> <p>The tree data is set using the <code>tree-model</code> attribute, which accepts either a node object or an array of node objects. A Node object is a regular javascript object which has a <code>children</code> array property (children is the default name, it can be overridden using the tree options). </p> <p>Selected node: <code>{{selectedNode?selectedNode.label:"N/A"}}</code></p> </div> </div> <div class="row"> <tabset> <tab heading="Markup" > <pre class="code" apply-content="classic-html" highlight-lang="html"></pre> </tab> <tab heading="JavaScript"> <pre class="code" apply-content="classic-js" highlight-lang="js"></pre> </tab> </tabset> </div> <script save-content="classic-js"> function Classic($scope) { $scope.treedata=createSubTree(3, 4, ""); $scope.showSelected = function(sel) { $scope.selectedNode = sel; }; } </script> </section> <section id="as-attribute" ng-controller="AsAttribute"> <div class="page-header"> <h1>As an Attribute <small>(Alternative to a Custom Element)</small></h1> </div> <div class="row"> <div class="col-md-6 show-grid"> <div class="panel panel-default"> <div class="panel-body"> <div class="example-caption">EXAMPLE:</div> <div save-content="as-attribute-html"> <div treecontrol class="tree-classic" tree-model="treedata" on-selection="showSelected(node)"> label: {{node.label}} ({{node.id}}) </div> </div> </div> </div> </div> <div class="col-md-6"> <p>Using the tree control as an attribute is as easy as using a div and adding a <code>treecontrol</code> attribute to it</p> <p>Note that you have to include the <code>tree-control-attribute.css</code> file instead of the <code>tree-control.css</code> as the CSS selectors are quite different between the two styles of usage.</p> <p>Selected node: <code>{{selectedNode?selectedNode.label:"N/A"}}</code></p> </div> </div> <div class="row"> <tabset> <tab heading="Markup" > <pre class="code" apply-content="as-attribute-html" highlight-lang="html"></pre> </tab> <tab heading="JavaScript"> <pre class="code" apply-content="as-attribute-js" highlight-lang="js"></pre> </tab> </tabset> </div> <script save-content="as-attribute-js"> function AsAttribute($scope) { $scope.treedata=createSubTree(3, 4, ""); $scope.showSelected = function(sel) { $scope.selectedNode = sel; }; } </script> </section> <section id="labels-template" ng-controller="LabelsTemplate"> <div class="page-header"> <h1>Tree Label Templates <small>(Customize the tree labels)</small></h1> </div> <div class="row"> <div class="col-md-6 show-grid"> <div class="panel panel-default"> <div class="panel-body"> <div class="example-caption">EXAMPLE:</div> <div save-content="labels-template-html"> <treecontrol class="tree-classic" tree-model="treedata" on-selection="showSelected(node)"> <span style="color: {{getColor(node)}}">{{node.label}} - index: {{$index}}</span> </treecontrol> </div> </div> </div> </div> <div class="col-md-6"> <p>Taking control of the tree labels is as simple as with <code>ng-repeat</code> - you include a template in the tree control tag.</p> <p>Special properties are exposed to the local scope of each template, including the current node as <code>node</code>.</p> <p>Selected node: <code>{{selectedNode?selectedNode.label:"N/A"}}</code></p> </div> </div> <table class="table table-bordered table-striped"> <thead><tr><td>Variable</td><td>Type</td><td>Details</td></tr></thead> <tr><td><code>node</code></td><td><span class="label type-hint-object">Object</span></td><td>The current node the label represents.</td></tr> <tr><td><code>$parentNode</code></td><td><span class="label type-hint-object">Object</span></td><td>The parent of the current node.</td></tr> <tr><td><code>$index</code></td><td><span class="label type-hint-number">number</span></td><td>iterator offset of the repeated element under one parent node(0..length-1).</td></tr> <tr><td><code>$first</code></td><td><span class="label type-hint-boolean">boolean</span></td><td>true if the repeated element is first in the iterator.</td></tr> <tr><td><code>$middle</code></td><td><span class="label type-hint-boolean">boolean</span></td><td>true if the repeated element is between the first and last in the iterator.</td></tr> <tr><td><code>$last</code></td><td><span class="label type-hint-boolean">boolean</span></td><td>true if the repeated element is last in the iterator.</td></tr> <tr><td><code>$odd</code></td><td><span class="label type-hint-boolean">boolean</span></td><td>true if the iterator position $index is even (otherwise false).</td></tr> <tr><td><code>$even</code></td><td><span class="label type-hint-boolean">boolean</span></td><td>true if the iterator position $index is odd (otherwise false).</td></tr> </table> <div class="row"> <tabset> <tab heading="Markup" > <pre class="code" apply-content="labels-template-html" highlight-lang="html"></pre> </tab> <tab heading="JavaScript"> <pre class="code" apply-content="labels-template-js" highlight-lang="js"></pre> </tab> </tabset> </div> <script save-content="labels-template-js"> function LabelsTemplate($scope) { $scope.treedata=createSubTree(3, 4, ""); $scope.getColor = function(node) { return ["#a40", "#04a", "#990", "#0a4"][node.i % 4]; }; $scope.showSelected = function(sel) { $scope.selectedNode = sel; }; } </script> </section> <section id="parent" ng-controller="Parent"> <div class="page-header"> <h1>Tree Label Scope <small>(as a child of the controller scope)</small></h1> </div> <div class="row"> <div class="col-md-6 show-grid"> <div class="panel panel-default"> <div class="panel-body"> <div class="example-caption">EXAMPLE:</div> <div save-content="classic-html"> <treecontrol class="tree-classic" tree-model="treedata" on-selection="showSelected(node)"> <button ng-click="buttonClick($event, node)">Click Me!</button> label: {{node.label}} ({{node.id}} ) {{$index}} </treecontrol> </div> </div> </div> </div> <div class="col-md-6"> <p>The scope used to compile the tree labels is a child scope of the controller (used to compile the tree-control directive). As such, in the tree label scope you have access to all the properties and methods defined in the controller scope. This example shows how to access a method in the parent scope from the label template.</p> <p>Selected node: <code>{{selectedNode?selectedNode.label:"N/A"}}</code></p> <p>Last clicked: <code>{{lastClicked ? lastClicked.label : "N/A"}}</code></p> </div> </div> <div class="row"> <tabset> <tab heading="Markup" > <pre class="code" apply-content="classic-html" highlight-lang="html"></pre> </tab> <tab heading="JavaScript"> <pre class="code" apply-content="classic-js" highlight-lang="js"></pre> </tab> </tabset> </div> <script save-content="classic-js"> function Parent($scope) { $scope.treedata=createSubTree(3, 4, ""); $scope.lastClicked = null; $scope.buttonClick = function($event, node) { $scope.lastClicked = node; $event.stopPropagation(); } $scope.showSelected = function(sel) { $scope.selectedNode = sel; }; } </script> </section> <section id="changing" ng-controller="Changing"> <div class="page-header"> <h1>Changing the live tree <small>(adding and removing nodes)</small></h1> </div> <div class="row"> <div class="col-md-6 show-grid"> <div class="panel panel-default"> <div class="panel-body"> <div class="example-caption">EXAMPLE:</div> <div save-content="changing-html"> <treecontrol class="tree-classic" tree-model="treedata"> label: {{node.label}} ({{node.id}}) </treecontrol> </div> </div> </div> </div> <div class="col-md-6"> <p>You can modify the <code>tree-model</code> bound tree, and the tree will update with the new structure</p> <p>For instance, adding nodes:</p> <ul> <li><a ng-click="addRoot()">Add a new root</a></li> <li><a ng-click="addChildToSecondRoot()">Add a child to the 2nd node</a></li> </ul> </div> </div> <div class="row"> <tabset> <tab heading="Markup" > <pre class="code" apply-content="changing-html" highlight-lang="html"></pre> </tab> <tab heading="JavaScript"> <pre class="code" apply-content="changing-js" highlight-lang="js"></pre> </tab> </tabset> </div> <script save-content="changing-js"> function Changing($scope) { $scope.treedata=createSubTree(3, 4, ""); $scope.addRoot = function() { $scope.treedata.push({label: "New Root", id:"some id", children: []}) }; $scope.addChildToSecondRoot = function() { $scope.treedata[1].children.push({label: "New Child", id:"some id", children: []}) }; } </script> </section> <section id="selected" ng-controller="Selected"> <div class="page-header"> <h1>Selected Node Binding <small>(selected-node)</small></h1> </div> <div class="row"> <div class="col-md-6 show-grid"> <div class="panel panel-default"> <div class="panel-body"> <div class="example-caption">EXAMPLE:</div> <div save-content="selected-html"> <treecontrol class="tree-classic" tree-model="treedata" selected-node="selected"> label: {{node.label}} ({{node.id}}) </treecontrol> </div> </div> </div> </div> <div class="col-md-6"> <p>The <code>selected-node</code> attribute of <code>treecontrol</code> is bound to the currently selected node object of the tree. Like any other Angular bound value, updating selected-node will set the tree selection, and clicking the tree (selecting a node) will update back the selected-node.</p> <p>Setting <code>selected-node</code> can also be used to set the default selected node of the tree.</p> <p>Note that if using multiple selection, the selected nodes are bound to an Array property <code>selected-nodes</code> instead of <code>selected-node</code>.</p> <p><a ng-click="selectNode(0)">select node 1</a><br> <a ng-click="selectNode(1)">select node 2</a><br> <a ng-click="selectNode(2)">select node 3</a><br> <a ng-click="selectNode(3)">select node 4</a><br> <a ng-click="clearSelected()">clear Selected</a></p> <p>Selected node: <code>{{selected.label}}</code></p> </div> </div> <div class="row"> <tabset> <tab heading="Markup" > <pre class="code" apply-content="selected-html" highlight-lang="html"></pre> </tab> <tab heading="JavaScript"> <pre class="code" apply-content="selected-js" highlight-lang="js"></pre> </tab> </tabset> </div> <script save-content="selected-js"> function Selected($scope) { $scope.treedata=createSubTree(3, 4, ""); $scope.selected = $scope.treedata[2]; $scope.selectNode = function(num) { $scope.selected = $scope.treedata[num]; }; $scope.clearSelected = function() { $scope.selected = undefined; } } </script> </section> <section id="expandedNodes" ng-controller="ExpandedNodes"> <div class="page-header"> <h1>Expanded Nodes Binding <small>(expanded-nodes)</small></h1> </div> <div class="row"> <div class="col-md-6 show-grid"> <div class="panel panel-default"> <div class="panel-body"> <div class="example-caption">EXAMPLE:</div> <div save-content="default-expanded-html"> <treecontrol class="tree-classic" tree-model="treedata" expanded-nodes="expandedNodes" options="opts"> label: {{node.label}} ({{node.id}}) </treecontrol> </div> </div> </div> </div> <div class="col-md-6"> <p>The <code>expanded-nodes</code> attribute of <code>treecontrol</code> is bound to the currently selected node object of the tree. Like any other Angular bound value, updating <code>expanded-nodes</code> will set the expanded nodes in the tree, and expanding or contracting nodes in the tree will update the <code>expanded-nodes</code> property.</p> <p>Setting <code>expanded-nodes</code> can also be used to set the default expanded nodes of the tree.</p> <p><a ng-click="setExpanded()">Expand 2, 3 and 3.3 (only)</a></p> <p>The currently expanded nodes:</p> <ul> <li ng-repeat="node in expandedNodes">{{node.label}}</li> </ul> </div> </div> <div class="row"> <tabset> <tab heading="Markup" > <pre class="code" apply-content="default-expanded-html" highlight-lang="html"></pre> </tab> <tab heading="JavaScript"> <pre class="code" apply-content="default-expanded-js" highlight-lang="js"></pre> </tab> </tabset> </div> <script save-content="default-expanded-js"> function ExpandedNodes($scope) { $scope.treedata=createSubTree(3, 4, ""); $scope.expandedNodes = [$scope.treedata[1], $scope.treedata[3], $scope.treedata[3].children[2], $scope.treedata[3].children[2].children[1]]; $scope.setExpanded = function() { $scope.expandedNodes = [$scope.treedata[1], $scope.treedata[2], $scope.treedata[2].children[2] ]; }; } </script> </section> <section id="events" ng-controller="Events"> <div class="page-header"> <h1>Events <small>(on-expand & on-selection)</small></h1> </div> <div class="row"> <div class="col-md-6 show-grid"> <div class="panel panel-default"> <div class="panel-body"> <div class="example-caption">EXAMPLE:</div> <div save-content="events-html"> <treecontrol class="tree-classic" tree-model="treedata" on-selection="showSelected(node, selected, $parentNode, $index, $first, $middle, $last, $odd, $even)" on-node-toggle="showToggle(node, expanded, $parentNode, $index, $first, $middle, $last, $odd, $even)"> label: {{node.label}} ({{node.id}}) </treecontrol> </div> </div> </div> </div> <div class="col-md-6"> <P>The tree supports events for selection and expansion of nodes. The events are set using the <code>on-selection</code> and <code>on-node-toggle</code> attributes which values are evaluated as angular expressions (like <code>ng-click</code> value). The expression can use the <code>node</code> and <code>selected</code> variables (for on-selection) or the <code>node</code> and <code>expanded</code> variables (for on-node-toggle) for context of the clicked node and if it was selected / deselected or expanded / collapsed.</P> <p>Note the events are fired only on the clicked node. If using the tree in single selection mode and one node is selected, when selecting a different node only one on-selection event will be fired for the newly selected node. The old selected node will not be selected anymore without an on-selected event.</p> <p>In order to prevent selection of branches (folders) in the tree, set the <code>options.dirSelectable</code> to <code>false</code>. Clicking folder labels at this point will expand and contract the node.</p> <p>Events fired:</p> <ul id="events-listing"> </ul> </div> </div> <table class="table table-bordered table-striped"> <thead><tr><td>Variable</td><td>Type</td><td>Details</td></tr></thead> <tr><td><code>node</code></td><td><span class="label type-hint-object">Object</span></td><td>The current node the label represents.</td></tr> <tr><td><code>$parentNode</code></td><td><span class="label type-hint-object">Object</span></td><td>The parent of the current node.</td></tr> <tr><td><code>$index</code></td><td><span class="label type-hint-number">number</span></td><td>iterator offset of the repeated element under one parent node(0..length-1).</td></tr> <tr><td><code>$first</code></td><td><span class="label type-hint-boolean">boolean</span></td><td>true if the repeated element is first in the iterator.</td></tr> <tr><td><code>$middle</code></td><td><span class="label type-hint-boolean">boolean</span></td><td>true if the repeated element is between the first and last in the iterator.</td></tr> <tr><td><code>$last</code></td><td><span class="label type-hint-boolean">boolean</span></td><td>true if the repeated element is last in the iterator.</td></tr> <tr><td><code>$odd</code></td><td><span class="label type-hint-boolean">boolean</span></td><td>true if the iterator position $index is even (otherwise false).</td></tr> <tr><td><code>$even</code></td><td><span class="label type-hint-boolean">boolean</span></td><td>true if the iterator position $index is odd (otherwise false).</td></tr> <tr><td><code>selected</code></td><td><span class="label type-hint-boolean">boolean</span></td><td>true if the node is selected, false if it is de-selected. Only applies to the on-selection event.</td></tr> <tr><td><code>expanded</code></td><td><span class="label type-hint-boolean">boolean</span></td><td>true if the node is expanding, false if the node is contracting. Only applies to the on-node-toggle event.</td></tr> </table> <div class="row"> <tabset> <tab heading="Markup" > <pre class="code" apply-content="events-html" highlight-lang="html"></pre> </tab> <tab heading="JavaScript"> <pre class="code" apply-content="events-js" highlight-lang="js"></pre> </tab> </tabset> </div> <script save-content="events-js"> function Events($scope) { $scope.treedata=createSubTree(3, 4, ""); $scope.showToggle = function(node, expanded, $parentNode, $index, $first, $middle, $last, $odd, $even) { var parent = $parentNode?("child of: " + $parentNode.label):"root node"; var location = $first?"first":($last?"last":("middle node at index " + $index)); var oddEven = $odd?"odd":"even"; $("#events-listing").append("<li>"+node.label+ (expanded?" expanded":" collapsed") +" (" + parent + ", " + location +", " + oddEven + ")</li>"); }; $scope.showSelected = function(node, selected, $parentNode, $index, $first, $middle, $last, $odd, $even) { var parent = $parentNode?("child of: " + $parentNode.label):"root node"; var location = $first?"first":($last?"last":("middle node at index " + $index)); var oddEven = $odd?"odd":"even"; $("#events-listing").append("<li>"+node.label+ (selected?" selected":" deselected") +" (" + parent + ", " + location +", " + oddEven + ")</li>"); }; } </script> </section> <section id="multi-selection" ng-controller="MultiSelection"> <div class="page-header"> <h1>Multi Selection <small>(options.multiSelect & selected-nodes)</small></h1> </div> <div class="row"> <div class="col-md-6 show-grid"> <div class="panel panel-default"> <div class="panel-body"> <div class="example-caption">EXAMPLE:</div> <div save-content="multi-selection-html"> <treecontrol class="tree-classic" tree-model="treedata" selected-nodes="selectedNodes" on-selection="showSelected(node, selected)" options="treeOptions"> label: {{node.label}} ({{node.id}}) </treecontrol> </div> </div> </div> </div> <div class="col-md-6"> <P>The tree control supports multi-selection using the <code>options.multiSelect</code> option and the <code>selected-nodes</code> attribute (instead of the <code>selected-node</code> attribute in single selection mode). <code>selected-nodes</code> is expected to be an Array which will contain the selected nodes. When using multi-selection, selecting a node adds it to the selected-nodes array and a second click remove it from the array.</p> <div class="row"> <div class="col-md-6"> <p>Selected Nodes:</p> <ul id="multi-selection-listing"> <li ng-repeat="node in selectedNodes">{{node.label}}</li> </ul> </div> <div class="col-md-6"> <p>Selection Events:</p> <ul id="multi-selection-events-listing"> </ul> </div> </div> </div> </div> <div class="row"> <tabset> <tab heading="Markup" > <pre class="code" apply-content="multi-selection-html" highlight-lang="html"></pre> </tab> <tab heading="JavaScript"> <pre class="code" apply-content="multi-selection-js" highlight-lang="js"></pre> </tab> </tabset> </div> <script save-content="multi-selection-js"> function MultiSelection($scope) { $scope.treeOptions = {multiSelection: true}; $scope.treedata=createSubTree(3, 4, ""); $scope.selectedNodes = []; $scope.showSelected = function(node, selected) { $("#multi-selection-events-listing").append("<li>"+node.label+ (selected?" selected":" deselected") + "</li>"); }; } </script> </section> <section id="dirSelection" ng-controller="DirSelection"> <div class="page-header"> <h1>Clicking Labels Expand & Collapse <small>(options.dirSelectable)</small></h1> </div> <div class="row"> <div class="col-md-6 show-grid"> <div class="panel panel-default"> <div class="panel-body"> <div class="example-caption">EXAMPLE:</div> <div save-content="dir-selection-html"> <treecontrol class="tree-classic" tree-model="treedata" options="opts" on-selection="showSelected(node)"> label: {{node.label}} ({{node.id}}) </treecontrol> </div> </div> </div> </div> <div class="col-md-6"> <p>In order to prevent selection of branches (folders) in the tree, set the <code>options.dirSelectable</code> to <code>false</code>. Clicking folder labels at this point will expand and contract the node.</p> <p>Selected node: <code>{{selectedNode?selectedNode.label:"N/A"}}</code></p> </div> </div> <div class="row"> <tabset> <tab heading="Markup" > <pre class="code" apply-content="dir-selection-html" highlight-lang="html"></pre> </tab> <tab heading="JavaScript"> <pre class="code" apply-content="dir-selection-js" highlight-lang="js"></pre> </tab> </tabset> </div> <script save-content="dir-selection-js"> function DirSelection($scope) { $scope.treedata=createSubTree(3, 4, ""); $scope.opts = { dirSelectable: false }; $scope.showSelected = function(sel) { $scope.selectedNode = sel; }; } </script> </section> <section id="isSelectable" ng-controller="IsSelectable"> <div class="page-header"> <h1>Disabling Selection of Nodes <small>(options.isSelectable)</small></h1> </div> <div class="row"> <div class="col-md-6 show-grid"> <div class="panel panel-default"> <div class="panel-body"> <div class="example-caption">EXAMPLE:</div> <div save-content="dir-selection-html"> <treecontrol class="tree-classic" tree-model="treedata" options="opts" on-selection="showSelected(node)"> label: {{node.label}} ({{node.id}}) </treecontrol> </div> </div> </div> </div> <div class="col-md-6"> <p>To restrict which nodes are selectable on the tree, define the <code>options.isSelectable(node)</code> function.</p> <p>Example disables the selection of any node on or under the <code>Node 1</code> node</p> <p>Selected node: <code>{{selectedNode?selectedNode.label:"N/A"}}</code></p> </div> </div> <div class="row"> <tabset> <tab heading="Markup" > <pre class="code" apply-content="dir-selection-html" highlight-lang="html"></pre> </tab> <tab heading="JavaScript"> <pre class="code" apply-content="dir-selection-js" highlight-lang="js"></pre> </tab> </tabset> </div> <script save-content="dir-selection-js"> function IsSelectable($scope) { $scope.treedata=createSubTree(3, 4, ""); $scope.opts = { isSelectable: function(node) { return node.label.indexOf("Node 1") !== 0; } }; $scope.showSelected = function(sel) { $scope.selectedNode = sel; }; } </script> </section> <section id="light" ng-controller="Light"> <div class="page-header"> <h1>Light Style <small>(Basic style, default configuration)</small></h1> </div> <div class="row"> <div class="col-md-6 show-grid"> <div class="panel panel-default"> <div class="panel-body"> <div class="example-caption">EXAMPLE:</div> <div save-content="light-html"> <treecontrol class="tree-light" tree-model="treedata" on-selection="showSelected(node)"> label: {{node.label}} ({{node.id}}) </treecontrol> </div> </div> </div> </div> <div class="col-md-6"> <p>Light style of the tree control, set using the class <code>tree-light</code>.</p> <p>Click on the folder icons to open and close the tree nodes. Click on the node label to select a node in the tree.</p> <p>Selected node: <code>{{selectedNode?selectedNode.label:"N/A"}}</code></p> </div> </div> <div class="row"> <tabset> <tab heading="Markup" > <pre class="code" apply-content="light-html" highlight-lang="html"></pre> </tab> <tab heading="JavaScript"> <pre class="code" apply-content="light-js" highlight-lang="js"></pre> </tab> </tabset> </div> <script save-content="light-js"> function Light($scope) { $scope.treedata=createSubTree(3, 4, ""); $scope.showSelected = function(sel) { $scope.selectedNode = sel; }; } </script> </section> <section id="dark" ng-controller="Dark"> <div class="page-header"> <h1>Dark Style <small>(Basic style, default configuration)</small></h1> </div> <div class="row"> <div class="col-md-6 show-grid"> <div class="panel panel-default"> <div class="panel-body" style="background-color: #555;"> <div class="example-caption">EXAMPLE:</div> <div save-content="dark-html"> <!-- Note that the tree does not set the background color. We inject it from the wrapper div. --> <div style="background-color: #555;"> <treecontrol class="tree-dark" tree-model="treedata" on-selection="showSelected(node)"> label: {{node.label}} ({{node.id}}) </treecontrol> </div> </div> </div> </div> </div> <div class="col-md-6"> <p>Dark style of the tree control, set using the class <code>tree-dark</code>. The style does not include the background color, instead, inject your own background color using a wrapper div element.</p> <p>Click on the folder icons to open and close the tree nodes. Click on the node label to select a node in the tree.</p> <p>Selected node: <code>{{selectedNode?selectedNode.label:"N/A"}}</code></p> </div> </div> <div class="row"> <tabset> <tab heading="Markup" > <pre class="code" apply-content="dark-html" highlight-lang="html"></pre> </tab> <tab heading="JavaScript"> <pre class="code" apply-content="dark-js" highlight-lang="js"></pre> </tab> </tabset> </div> <script save-content="dark-js"> function Dark($scope) { $scope.treedata=createSubTree(3, 4, ""); $scope.showSelected = function(sel) { $scope.selectedNode = sel; }; } </script> </section> <section id="custom-css" ng-controller="CustomCss"> <div class="page-header"> <h1>Custom Css Classes <small>(options.injectClasses)</small></h1> </div> <div class="row"> <div class="col-md-6 show-grid"> <div class="panel panel-default"> <div class="panel-body"> <div class="example-caption">EXAMPLE:</div> <div save-content="custom-css-html"> <style> .c-ul {border: 1px solid #abcdef;} .c-li {background-color: #defacb} .c-liSelected {background-color: #fedbca} .c-iExpanded {border: 1px solid #77a} .c-iCollapsed {border: 1px solid #7c7} .c-iLeaf {border: 1px solid #a77} treecontrol.tree-classic li .tree-label.c-label {color: #44c} treecontrol.tree-classic li .tree-selected.c-labelSelected {background-color: yellow} </style> <treecontrol class="tree-classic" tree-model="treedata" options="opts"> label: {{node.label}} ({{node.id}}) </treecontrol> </div> </div> </div> </div> <div class="col-md-6"> <p>The <code>options.injectClasses</code> option allows to add custom CSS classes on the tree DOM. The selected classes are</p> <ul> <li><code>ul</code> - inject classes into the ul elements (branch elements)</li> <li><code>li</code> - inject classes into the li elements (both branch and leaf elements)</li> <li><code>liSelected</code> - inject classes into the li elements of the selected node</li> <li><code>iExpanded</code> - inject classes into the 'i' element for the expanded nodes (the icon)</li> <li><code>iCollapsed</code> - inject classes into the 'i' element for the collapsed nodes</li> <li><code>iLeaf</code> - inject classes into the 'i' element for leaf nodes</li> <li><code>label</code> - inject classes into the div element around the label</li> <li><code>labelSelected</code> - inject classes into the div element around the label only when the node is selected</li> </ul> </div> </div> <div class="row"> <tabset> <tab heading="Markup" > <pre class="code" apply-content="custom-css-html" highlight-lang="html"></pre> </tab> <tab heading="JavaScript"> <pre class="code" apply-content="custom-css-js" highlight-lang="js"></pre> </tab> </tabset> </div> <script save-content="custom-css-js"> function CustomCss($scope) { $scope.treedata=createSubTree(3, 4, ""); $scope.opts = { injectClasses: { "ul": "c-ul", "li": "c-li", "liSelected": "c-liSelected", "iExpanded": "c-iExpanded", "iCollapsed": "c-iCollapsed", "iLeaf": "c-iLeaf", "label": "c-label", "labelSelected": "c-labelSelected" } }; } </script> </section> <section id="children" ng-controller="Children"> <div class="page-header"> <h1>Custom Children <small>(options.nodeChildren)</small></h1> </div> <div class="row"> <div class="col-md-6 show-grid"> <div class="panel panel-default"> <div class="panel-body"> <div class="example-caption">EXAMPLE:</div> <div save-content="children-html"> <treecontrol class="tree-classic" tree-model="treedata" options="opts"> label: {{node.label}} ({{node.id}}) </treecontrol> </div> </div> </div> </div> <div class="col-md-6"> <p>Angular tree control assumes that the tree nodes have a <code>children</code> array property for the children of the node. You can override the children property name using the tree <code>nodeChildren</code> property of the tree options.</p> </div> </div> <div class="row"> <tabset> <tab heading="Markup" > <pre class="code" apply-content="children-html" highlight-lang="html"></pre> </tab> <tab heading="JavaScript"> <pre class="code" apply-content="children-js" highlight-lang="js"></pre> </tab> </tabset> </div> <script save-content="children-js"> function Children($scope) { $scope.treedata=[ {id:"id1", label: "Node 1", links: [ {id:"id1.1", label: "Node 1.1", links: {}}, {id:"id1.2", label: "Node 1.1", links: {}} ]}, {id:"id2", label: "Node 2", links: []}, {id:"id3", label: "Node 3", links: []}, {id:"id4", label: "Node 4", links: []} ]; $scope.opts = { nodeChildren: "links" }; } </script> </section> <section id="isleaf" ng-controller="Isleaf"> <div class="page-header"> <h1>Custom Branch / Leaf <small>(options.isLeaf)</small></h1> </div> <div class="row"> <div class="col-md-6 show-grid"> <div class="panel panel-default"> <div class="panel-body"> <div class="example-caption">EXAMPLE:</div> <div save-content="isleaf-html"> <treecontrol class="tree-classic" tree-model="treedata" options="opts"> label: {{node.label}} ({{node.id}}) </treecontrol> </div> </div> </div> </div> <div class="col-md-6"> <p>the <code>isLeaf</code> option allows taking control of the selection if a node is a branch (folder) or a leaf (File). This method returns a boolean, where <code>true</code> indicates a leaf, <code>false</code> indicates a branch.</p> </div> </div> <div class="row"> <tabset> <tab heading="Markup" > <pre class="code" apply-content="isleaf-html" highlight-lang="html"></pre> </tab> <tab heading="JavaScript"> <pre class="code" apply-content="isleaf-js" highlight-lang="js"></pre> </tab> </tabset> </div> <script save-content="isleaf-js"> function Isleaf($scope) { $scope.treedata=createSubTree(3, 4, ""); $scope.opts = { isLeaf: function(node) { return node.i % 2 == 0; } }; } </script> </section> <section id="sorting" ng-controller="Sorting"> <div class="page-header"> <h1>Sorting tree nodes <small>(order-by, reserve-order)</small></h1> </div> <div class="row"> <div class="col-md-6 show-grid"> <div class="panel panel-default"> <div class="panel-body"> <div class="example-caption">EXAMPLE:</div> <div save-content="sorting-html"> <treecontrol class="tree-classic" tree-model="treedata" order-by="label" reverse-order="{{reverse}}"> label: {{node.label}} ({{node.id}}) </treecontrol> </div> </div> </div> </div> <div class="col-md-6"> <p>The <code>order-by</code> and <code>reverse-order</code> properties allows controlling the sorting of the tree nodes. The value of those attributes is used with the <code>ng-repeat</code> orderBy filter - see more details at the <a href="https://code.angularjs.org/1.2.0-rc.3/docs/api/ng.filter:orderBy">Angular JS orderBy</a> docs.</p> <p>The sorting is done for each branch individually (sorting does not change the stucture of the tree itself).</p> <input type="checkbox" ng-model="reverse"/> Reverse Order </div> </div> <div class="row"> <tabset> <tab heading="Markup" > <pre class="code" apply-content="sorting-html" highlight-lang="html"></pre> </tab> <tab heading="JavaScript"> <pre class="code" apply-content="sorting-js" highlight-lang="js"></pre> </tab> </tabset> </div> <script save-content="sorting-js"> function Sorting($scope) { $scope.treedata=createSubTree(3, 4, ""); $scope.reverse = true; } </script> </section> <section id="filtering" ng-controller="Filtering"> <div class="page-header"> <h1>Filtering tree nodes <small>(filter-expression, filter-comparator)</small></h1> </div> <div class="row"> <div class="col-md-6 show-grid"> <div class="panel panel-default"> <div class="panel-body"> <div class="example-caption">EXAMPLE:</div> <div save-content="filtering-html"> <treecontrol class="tree-classic" tree-model="treedata" filter-expression="predicate" filter-comparator="comparator"> label: {{node.label}} ({{node.id}}) </treecontrol> </div> </div> </div> </div> <div class="col-md-6"> <p>The <code>filter-expression</code> and <code>filter-comparator</code> properties allows filtering the nodes of the tree. The value of those attributes is used with the <code>ng-repeat</code> Filter filter - see more details at the <a href="https://code.angularjs.org/1.2.25/docs/api/ng/filter/filter">Angular JS Filter</a> docs.</p> <p>The filter is done for each branch individually.</p> <p>The filter expression (predicate) is used for selecting nodes from the tree to display. It can be a string, object or a function. If a string, it is used to match values of the node properties. If an object, each property of the expression object is used to match values of the node properties with the same name. A function can be used to write arbitrary filters, and will be invoked for each node of the tree.</p> <p>The filter comparator is used in determining if the expected value (from the filter expression) and actual value (from the object in the array) should be considered a match. If false, it looks for substring match in a case insensitive way (the default). If true, it looks for exact match. If a function, the function will be given the object value and the predicate value to compare and should return true if the item should be included in filtered result.</p> <input type="text" ng-model="predicate"/> Filter expression (string)<br> <input type="checkbox" ng-model="comparator"/> Filter comparator (true or false) </div> </div> <div class="row"> <tabset> <tab heading="Markup" > <pre class="code" apply-content="filtering-html" highlight-lang="html"></pre> </tab> <tab heading="JavaScript"> <pre class="code" apply-content="filtering-js" highlight-lang="js"></pre> </tab> </tabset> </div> <script save-content="filtering-js"> function Filtering($scope) { $scope.treedata=createSubTree(3, 4, ""); $scope.predicate = "Node 1"; $scope.comparator = false; } </script> </section> <section id="equality" ng-controller="Equality"> <div class="page-header"> <h1>Custom Equality <small>(options.equality)</small></h1> </div> <div class="row"> <div class="col-md-6 show-grid"> <div class="panel panel-default"> <div class="panel-body"> <div class="example-caption">EXAMPLE:</div> <div save-content="equality-html"> <treecontrol class="tree-classic" tree-model="treedata" options="opts"> label: {{node.name}} ({{node.age}}) </treecontrol> </div> </div> </div> </div> <div class="col-md-6"> <p>The angular tree control is using an equality function to determine if two nodes are equal, The build it function checks for equality of the node members, ignoring the children property.</p> <p>In some cases, it is required to replace the equality function. Some examples include</p> <ul> <li>If multiple nodes exist in the three that are identical except for their parents and children, the default function will confuse between them. In such as case, it is recommended to replace the function with the === operator (as in this example).</li> <li>If you have an id property for nodes that can be relayed on for node uniqueness and identification, using a custom equality function that checks for that id will result in better performance.</li> </ul> </div> </div> <div class="row"> <tabset> <tab heading="Markup" > <pre class="code" apply-content="equality-html" highlight-lang="html"></pre> </tab> <tab heading="JavaScript"> <pre class="code" apply-content="equality-js" highlight-lang="js"></pre> </tab> </tabset> </div> <script save-content="equality-js"> function Equality($scope) { $scope.treedata=[ { "name" : "Joe", "age" : "21", "children" : [ { "name" : "Smith", "age" : "42", "children" : [] }, { "name" : "Joe", "age" : "21", "children" : [ { "name" : "Jenifer", "age" : "23", "children" : [ { "name" : "Dani", "age" : "32", "children" : [] }, { "name" : "Max", "age" : "34", "children" : [] } ]} ]} ]}, { "name" : "Albert", "age" : "33", "children" : [] }, { "name" : "Ron", "age" : "29", "children" : [] } ]; $scope.opts = { equality: function(node1, node2) { return node1 === node2; } } } </script> </section> </div> <div class="col-md-3"> <ul nav class="nav docs-sidenav"> <!--<li class="active"><a href="#as-attribute">classic</a></li>--> </ul> </div> </div> <footer class="docs-footer"> <p>Designed and built by <a href="http://wix.com">Wix.com</a> team.</p> <p>Code licensed under <a href="https://github.com/angular-ui/bootstrap/blob/master/LICENSE">MIT License</a>.</p> <p>Checkout Wix developer resources <a href="http://dev.wix.com">dev.wix.com</a> and <a href="http://wix.io">wix.io</a>.</p> </footer> <script> var entityMap = { "&": "&", "<": "<", ">": ">", '"': '"', "'": ''', "/": '/' }; function escapeHtml(string) { return String(string).replace(/[&<>"'\/]/g, function (s) { return entityMap[s]; }); } var nonSpace = /\S/; function trimIndent(content) { var lines = content.split("\n"); var begin = 0; var end = lines.length-1; while ((nonSpace.exec(lines[begin]) == null) && (begin < lines.length)) begin = begin + 1; while ((nonSpace.exec(lines[end]) == null) && end >= begin) end = end - 1; var ident = nonSpace.exec(lines[begin]).index; var formatted = ""; for (var i = begin; i <= end; i++) { formatted = formatted + lines[i].slice(ident-1) + ((i < end)?"\n":""); } return formatted; } var example = angular.module("example", ["treeControl", "ui.bootstrap", "template/tabs/tab.html", "template/tabs/tabset.html"]) .factory("$savedContent", function() { return []; }) .directive("saveContent", function($savedContent) { return { restrict: "A", compile: function($element, $attrs) { var content = $element.html(); $savedContent[$attrs.saveContent] = content; } } }) .directive("applyContent", function($savedContent) { return { restrict: "EAC", compile: function($element, $attrs) { return function($scope, $element, $attrs) { var content = $savedContent[$attrs.applyContent]; var lang = $attrs.highlightLang; if (lang == "html") content = escapeHtml(content); content = trimIndent(content); var pre = prettyPrintOne(content, lang); $element.html(pre); } } } }) .directive("nav", function() { return { restrict: "A", compile: function($element) { var sections = $("section"); angular.forEach(sections, function(section) { var $section = $(section); var id = $section.attr('id'); var titleHtml = $section.find("h1").html(); titleHtml = titleHtml.slice(0, titleHtml.indexOf("<")).trim(); $element.append("<li><a href='#"+id+"'>"+titleHtml+"</a></li>") }) } } }) ; function createSubTree(level, width, prefix) { if (level > 0) { var res = []; for (var i=1; i <= width; i++) res.push({ "label" : "Node " + prefix + i, "id" : "id"+prefix + i, "i": i, "children": createSubTree(level-1, width, prefix + i +".") }); return res; } else return []; } </script> </body> </html>