2

Looking to implement folder hierarchy in Angular:

enter image description here

I'm implementing this via custom directive that references itself inside its template.

Currently it's going into infinite loop with this setup:

<!-- index.html -->
<subfolders folder="default_folder"></subfolders>

This is the <subfolders> directive:

//subfoldersDirective.js
angular.module('app').directive('subfolders', subfolders);
function subfolders() {

    var directive = {
        restrict: 'AE',
        scope: {
            folder: '=',
        },
        templateUrl: '/pathto/subfoldersDirective.html',
        controller: DirCtrl,
        controllerAs: 'vm'
    };

    return directive;

    function DirCtrl($scope) {
        var vm = this;
        vm.folder = $scope.folder;
    }

}

and its template:

<!-- folderDirective.html -->
<div ng-repeat="folder in vm.folder.subfolders">
    {{ folder.name }}
    <button ng-click="folder.is_open = true">Open folder</button>
    <div ng-if="folder.is_open">
       <!-- This is the problem line -->
       <subfolders folder="folder"></subfolders>
    </div>
</div>

In the template, <subfolders> should only get rendered after the button is clicked which triggers ng-if="folder.is_open". I guess Angular does not know this when it compiles the directive. It goes into infinite loop, even though it technically should not.

Is there a way to make it work with the directive? The logic is a bit more complex in the real app, this is why I'm looking to make it work with the directive.

I'm currently using Angular 1.2.26.

Websirnik
  • 1,372
  • 3
  • 21
  • 35

1 Answers1

4

You can do this, but you need to override the compile behavior of the directive. You need to remove contents of the directive element during the compilation step, and then compile and reattach it during the post-link step. I have used the compile function below with great success:

function compile(element) {
    var contents = element.contents().remove();
    var contentsLinker;

    return function (scope, iElement) {
        if (angular.isUndefined(contentsLinker)) {
            contentsLinker = $compile(contents);
        }

        contentsLinker(scope, function (clonedElement) {
            iElement.append(clonedElement);
        });
    };
}

I based this function on this post, which is probably more comprehensive if you need a pre-link function.

Community
  • 1
  • 1
John Bledsoe
  • 17,142
  • 5
  • 42
  • 59