|
30 | 30 | scope: { |
31 | 31 | treeModel: "=", |
32 | 32 | selectedNode: "=?", |
| 33 | + expandedNodes: "=?", |
33 | 34 | onSelection: "&", |
34 | 35 | onNodeToggle: "&", |
35 | 36 | options: "=?", |
|
67 | 68 | ensureDefault($scope.options, "equality", defaultEquality); |
68 | 69 | ensureDefault($scope.options, "isLeaf", defaultIsLeaf); |
69 | 70 |
|
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]; |
75 | 75 | } |
76 | 76 | $scope.parentScopeOfTree = $scope.$parent; |
77 | 77 |
|
|
83 | 83 | injectSelectionClass = " " + liSelectionClass; |
84 | 84 | if ($scope.options.isLeaf(node)) |
85 | 85 | return "tree-leaf" + injectSelectionClass; |
86 | | - if ($scope.expandedNodes[this.$id]) |
| 86 | + if ($scope.expandedNodesMap[this.$id]) |
87 | 87 | return "tree-expanded" + injectSelectionClass; |
88 | 88 | else |
89 | 89 | return "tree-collapsed" + injectSelectionClass; |
90 | 90 | }; |
91 | 91 |
|
92 | 92 | $scope.iBranchClass = function() { |
93 | | - if ($scope.expandedNodes[this.$id]) |
| 93 | + if ($scope.expandedNodesMap[this.$id]) |
94 | 94 | return classIfDefined($scope.options.injectClasses.iExpanded); |
95 | 95 | else |
96 | 96 | return classIfDefined($scope.options.injectClasses.iCollapsed); |
97 | 97 | }; |
98 | 98 |
|
99 | 99 | $scope.nodeExpanded = function() { |
100 | | - return !!$scope.expandedNodes[this.$id]; |
| 100 | + return !!$scope.expandedNodesMap[this.$id]; |
101 | 101 | }; |
102 | 102 |
|
103 | 103 | $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 | + } |
105 | 119 | if ($scope.onNodeToggle) |
106 | | - $scope.onNodeToggle({node: this.node, expanded: !!$scope.expandedNodes[this.$id]}); |
| 120 | + $scope.onNodeToggle({node: this.node, expanded: expanding}); |
107 | 121 | }; |
108 | 122 |
|
109 | 123 | $scope.selectNodeLabel = function( selectedNode ){ |
|
161 | 175 | } |
162 | 176 | }); |
163 | 177 |
|
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 | + } |
169 | 200 | } |
170 | | - } |
| 201 | + if (!found) |
| 202 | + newExpandedNodesMap[notFoundIds++] = newExNode; |
| 203 | + }); |
| 204 | + scope.expandedNodesMap = newExpandedNodesMap; |
171 | 205 | }); |
172 | 206 |
|
| 207 | +// scope.$watch('expandedNodesMap', function(newValue) { |
| 208 | +// |
| 209 | +// }); |
| 210 | + |
173 | 211 | //Rendering template for a root node |
174 | 212 | treemodelCntr.template( scope, function(clone) { |
175 | 213 | element.html('').append( clone ); |
|
197 | 235 | .directive("treeTransclude", function() { |
198 | 236 | return { |
199 | 237 | link: function(scope, element, attrs, controller) { |
200 | | - angular.forEach(scope.expandedNodes, function (node, id) { |
| 238 | + angular.forEach(scope.expandedNodesMap, function (node, id) { |
201 | 239 | 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; |
204 | 242 | } |
205 | 243 | }); |
206 | 244 | if (scope.options.equality(scope.node, scope.selectedNode)) { |
|
0 commit comments