I am trying to build a dynamic Tree component, i.e. like a folder structure. I would like the children to be load dynamically, so in contrast to other modules expecting the whole structure to be present during initialization, I would like to load the elements when needed.
Therefore I bind a controller function to the directive. This is my HTML:
<tree-model data="treedata" load-children="loadTree(n)" />
And this defines the tree-model directive
app.directive( 'treeModel', function( $compile, $log, $http ) {
return {
restrict: 'E',
scope: {
node: '=data',
loadChildren: '&'
},
link: function ( scope, element, attrs ) {
var template =
'<ul>' +
'<li ng-model="node">' +
'<span ng-switch="node.status">' +
'<i ng-switch-when="collapsed" class="collapsed" ng-click="selectNodeHead(node)">C</i>' +
'<i ng-switch-when="expanded" class="expanded" ng-click="selectNodeHead(node)">E</i>' +
'<i ng-switch-default="" class="normal">N</i> ' +
'</span>' +
'<span ng-class="node.selected">{{node.label}}</span>' +
'<span ng-repeat="c in node.children">' +
'<tree-model data="c" load-children="loadChildren(n)" />' +
'</span>' +
'</li>' +
'</ul>';
var repl = function() {
var newElement = angular.element(template);
$compile(newElement)(scope);
element.replaceWith(newElement);
}
scope.selectNodeHead = function(selectedNode) {
if (selectedNode.children && selectedNode.children.length) {
// Collapse
selectedNode.children = undefined;
selectedNode.hasChildren = true;
selectedNode.status = "collapsed";
} else {
// Expand
scope.loadChildren({n: selectedNode});
selectedNode.status ="expanded";
repl();
}
};
repl();
}
};
});
This is my controller:
app.controller('MyCtrl',
function ($scope, $log, $http) {
$scope.treedata = { "label": "Root", "status": "collapsed", "screen": "Root", "id": "999999", "hasChildren": true };
$scope.loadTree = function(node) {
$scope.output = "Node: " + node;
node.children =[
{ "label": "Child 1", "status": "collapsed", "screen": "Child 1", "id": "999997", "hasChildren": true},
{ "label": "Child 2", "status": "normal", "screen": "Child 2", "id": "999995", "hasChildren": false}
];
};
});
So I'd like to recursively build the tree. This works well for the first node and my controller function loadTree() gets the expected node as input. However, in the child step it calls loadTree(), but without passing node as parameter.
This seems to be somehow related to isolated scopes. If I do
scope.$parent.$parent.loadChildren({n: selectedNode});
instead of
scope.loadChildren({n: selectedNode});
in the expand part of the directive, the parameter passing works.
Here is a plunker to demonstrate the issue: http://plnkr.co/edit/i4vDuCd7efmweZ9IZXMD