Skip to content

Commit 43922b4

Browse files
committed
expaded-nodes binding
1 parent 1643ae6 commit 43922b4

File tree

3 files changed

+75
-32
lines changed

3 files changed

+75
-32
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,14 +104,14 @@ Attributes of angular treecontrol
104104
- element content : the template to evaluate against each node (and the parent scope of the tree) for the node label.
105105
- `tree-model` : [Node|Array[Node]] the tree data on the `$scope`. This can be an array of nodes or a single node.
106106
- `selected-node` : [Node] binding for the selected node in the tree. Updating this value updates the selection displayed in the tree. Selecting a node in the tree will update this value.
107+
- `expanded-nodes` : [Array[Node]] binding for the expanded nodes in the tree. Updating this value updates the nodes that are expanded in the tree.
107108
- `on-selection` : callback called whenever selecting a node in the tree. The callback argument is the selected node.
108109
- `on-node-toggle` : callback called whenever a node expands or collapses in the tree. The function arguments are the toggled node and a boolean which is true for expansion, false for collapse.
109110
- `options` : different options to customize the tree control.
110111
- `nodeChildren` : the name of the property of each node that holds the node children. Defaults to 'children'.
111112
- `dirSelectable` : are directories (nodes with children) selectable? If not, clicking on the dir label will expand and contact the dir. Defaults to `true`.
112113
- `equality` : the function used to determine equality between old nodes and new ones when checking whether a replacement node should be expanded and/or marked as selected. Defaults to a function which uses `angular.equals()` on everything except the property indicated in `nodeChildren`.
113114
- `isLeaf` : function (node) -> boolean used to determine if a node is a leaf or branch. The default function checks for existence of children of the node to determine leaf or branch.
114-
- `defaultExpanded` : array[node] - an array of nodes to be expanded in the tree by default
115115
- `injectClasses` : allows to inject additional CSS classes into the tree DOM
116116
- `ul` : inject classes into the ul elements
117117
- `li` : inject classes into the li elements

angular-tree-control.js

Lines changed: 57 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
scope: {
3131
treeModel: "=",
3232
selectedNode: "=?",
33+
expandedNodes: "=?",
3334
onSelection: "&",
3435
onNodeToggle: "&",
3536
options: "=?",
@@ -67,11 +68,10 @@
6768
ensureDefault($scope.options, "equality", defaultEquality);
6869
ensureDefault($scope.options, "isLeaf", defaultIsLeaf);
6970

70-
$scope.expandedNodes = {};
71-
if ($scope.options.defaultExpanded && angular.isArray($scope.options.defaultExpanded)) {
72-
for (var i=0; i < $scope.options.defaultExpanded.length; i++) {
73-
$scope.expandedNodes[""+i] = $scope.options.defaultExpanded[i];
74-
}
71+
$scope.expandedNodes = $scope.expandedNodes || [];
72+
$scope.expandedNodesMap = {};
73+
for (var i=0; i < $scope.expandedNodes.length; i++) {
74+
$scope.expandedNodesMap[""+i] = $scope.expandedNodes[i];
7575
}
7676
$scope.parentScopeOfTree = $scope.$parent;
7777

@@ -83,27 +83,41 @@
8383
injectSelectionClass = " " + liSelectionClass;
8484
if ($scope.options.isLeaf(node))
8585
return "tree-leaf" + injectSelectionClass;
86-
if ($scope.expandedNodes[this.$id])
86+
if ($scope.expandedNodesMap[this.$id])
8787
return "tree-expanded" + injectSelectionClass;
8888
else
8989
return "tree-collapsed" + injectSelectionClass;
9090
};
9191

9292
$scope.iBranchClass = function() {
93-
if ($scope.expandedNodes[this.$id])
93+
if ($scope.expandedNodesMap[this.$id])
9494
return classIfDefined($scope.options.injectClasses.iExpanded);
9595
else
9696
return classIfDefined($scope.options.injectClasses.iCollapsed);
9797
};
9898

9999
$scope.nodeExpanded = function() {
100-
return !!$scope.expandedNodes[this.$id];
100+
return !!$scope.expandedNodesMap[this.$id];
101101
};
102102

103103
$scope.selectNodeHead = function() {
104-
$scope.expandedNodes[this.$id] = ($scope.expandedNodes[this.$id] === undefined ? this.node : undefined);
104+
var expanding = $scope.expandedNodesMap[this.$id] === undefined;
105+
$scope.expandedNodesMap[this.$id] = (expanding ? this.node : undefined);
106+
if (expanding) {
107+
$scope.expandedNodes.push(this.node);
108+
}
109+
else {
110+
var index;
111+
for (var i=0; (i < $scope.expandedNodes.length) && !index; i++) {
112+
if ($scope.options.equality($scope.expandedNodes[i], this.node)) {
113+
index = i;
114+
}
115+
}
116+
if (index != undefined)
117+
$scope.expandedNodes.splice(index, 1);
118+
}
105119
if ($scope.onNodeToggle)
106-
$scope.onNodeToggle({node: this.node, expanded: !!$scope.expandedNodes[this.$id]});
120+
$scope.onNodeToggle({node: this.node, expanded: expanding});
107121
};
108122

109123
$scope.selectNodeLabel = function( selectedNode ){
@@ -161,15 +175,39 @@
161175
}
162176
});
163177

164-
scope.$watch('options.defaultExpanded', function(newValue) {
165-
scope.expandedNodes = {};
166-
if (scope.options.defaultExpanded && angular.isArray(scope.options.defaultExpanded)) {
167-
for (var i=0; i < scope.options.defaultExpanded.length; i++) {
168-
scope.expandedNodes[""+i] = scope.options.defaultExpanded[i];
178+
scope.$watchCollection('expandedNodes', function(newValue) {
179+
var notFoundIds = 0;
180+
var newExpandedNodesMap = {};
181+
var $liElements = element.find('li');
182+
var existingScopes = [];
183+
// find all nodes visible on the tree and the scope $id of the scopes including them
184+
angular.forEach($liElements, function(liElement) {
185+
var $liElement = angular.element(liElement);
186+
var liScope = $liElement.scope();
187+
existingScopes.push(liScope);
188+
});
189+
// iterate over the newValue, the new expanded nodes, and for each find it in the existingNodesAndScopes
190+
// if found, add the mapping $id -> node into newExpandedNodesMap
191+
// if not found, add the mapping num -> node into newExpandedNodesMap
192+
angular.forEach(newValue, function(newExNode) {
193+
var found = false;
194+
for (var i=0; (i < existingScopes.length) && !found; i++) {
195+
var existingScope = existingScopes[i];
196+
if (scope.options.equality(newExNode, existingScope.node)) {
197+
newExpandedNodesMap[existingScope.$id] = existingScope.node;
198+
found = true;
199+
}
169200
}
170-
}
201+
if (!found)
202+
newExpandedNodesMap[notFoundIds++] = newExNode;
203+
});
204+
scope.expandedNodesMap = newExpandedNodesMap;
171205
});
172206

207+
// scope.$watch('expandedNodesMap', function(newValue) {
208+
//
209+
// });
210+
173211
//Rendering template for a root node
174212
treemodelCntr.template( scope, function(clone) {
175213
element.html('').append( clone );
@@ -197,10 +235,10 @@
197235
.directive("treeTransclude", function() {
198236
return {
199237
link: function(scope, element, attrs, controller) {
200-
angular.forEach(scope.expandedNodes, function (node, id) {
238+
angular.forEach(scope.expandedNodesMap, function (node, id) {
201239
if (scope.options.equality(node, scope.node)) {
202-
scope.expandedNodes[scope.$id] = scope.node;
203-
scope.expandedNodes[id] = undefined;
240+
scope.expandedNodesMap[scope.$id] = scope.node;
241+
scope.expandedNodesMap[id] = undefined;
204242
}
205243
});
206244
if (scope.options.equality(scope.node, scope.selectedNode)) {

demo/demo.html

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -570,7 +570,7 @@ <h1>Custom Css Classes <small>(options.injectClasses)</small></h1>
570570

571571
<section id="defaultExpanded" ng-controller="DefaultExpanded">
572572
<div class="page-header">
573-
<h1>Default Expanded Nodes <small>(defaultExpanded)</small></h1>
573+
<h1>Expanded Nodes Binding <small>(expanded-nodes)</small></h1>
574574
</div>
575575
<div class="row">
576576
<div class="col-md-6 show-grid">
@@ -580,6 +580,7 @@ <h1>Default Expanded Nodes <small>(defaultExpanded)</small></h1>
580580
<div save-content="default-expanded-html">
581581
<treecontrol class="tree-classic"
582582
tree-model="treedata"
583+
expanded-nodes="expandedNodes"
583584
options="opts">
584585
label: {{node.label}} ({{node.id}})
585586
</treecontrol>
@@ -588,9 +589,15 @@ <h1>Default Expanded Nodes <small>(defaultExpanded)</small></h1>
588589
</div>
589590
</div>
590591
<div class="col-md-6">
591-
<p>In order set the nodes that are expanded (opened) when the tree initially renders, use the <code>defaultExpanded</code> option.</p>
592-
<p>The <code>defaultExpanded</code> is an array of the same node objects you use in the tree-model.</p>
593-
<a ng-click="setExpanded()">set expanded</a>
592+
<p>The <code>expanded-nodes</code> attribute of <code>treecontrol</code> is bound to the currently selected node object of the tree.
593+
Like any other Angular bound value, updating <code>expanded-nodes</code> will set the expanded nodes in the tree,
594+
and expanding or contracting nodes in the tree will update the <code>expanded-nodes</code> property.</p>
595+
<p>Setting <code>expanded-nodes</code> can also be used to set the default expanded nodes of the tree.</p>
596+
<p><a ng-click="setExpanded()">Expand 2, 3 and 3.3 (only)</a></p>
597+
<p>The currently expanded nodes:</p>
598+
<ul>
599+
<li ng-repeat="node in expandedNodes">{{node.label}}</li>
600+
</ul>
594601
</div>
595602
</div>
596603
<div class="row">
@@ -607,18 +614,16 @@ <h1>Default Expanded Nodes <small>(defaultExpanded)</small></h1>
607614
function DefaultExpanded($scope) {
608615
$scope.treedata=createSubTree(3, 4, "");
609616

610-
var defExpanded = [$scope.treedata[1],
617+
$scope.expandedNodes = [$scope.treedata[1],
611618
$scope.treedata[3],
612619
$scope.treedata[3].children[2],
613620
$scope.treedata[3].children[2].children[1]];
614621

615622
$scope.setExpanded = function() {
616-
$scope.opts.defaultExpanded = [$scope.treedata[1],
617-
$scope.treedata[2]];
618-
};
619-
620-
$scope.opts = {
621-
defaultExpanded: defExpanded
623+
$scope.expandedNodes = [$scope.treedata[1],
624+
$scope.treedata[2],
625+
$scope.treedata[2].children[2]
626+
];
622627
};
623628

624629
}
@@ -679,8 +684,8 @@ <h1>Custom Children <small>(options.nodeChildren)</small></h1>
679684
</script>
680685
</section>
681686

682-
conditional css class
683687
order nodes
688+
conditional css class
684689
set expanded - expanded nodes
685690
</div>
686691
<div class="col-md-3">

0 commit comments

Comments
 (0)