Recursively nested directives in angularjs

I tried to implement a recursively nested directive in angularjs.

I just made a directive <tree-dir>

and got this jsFiddle .

In my template tree_item_renderer.html

, if I replace ng-include

with <tree-dir>

, angular will go into an infinite loop on compilation (be careful, if you try it, it will slow down or stop your browser for a while).

Source: This question is about recursive trees in angular.

+3


source to share


2 answers


This answer explains and solves everything, here are the most important parts:

"When creating a tree view, the recursive directive is the best solution. However, when you make such a directive, you find that AngularJS gets into an infinite loop.

The solution for this is to let the directive remove the item at compile time and manually compile and add them in link events.

I found out about this in this thread and abstracted this functionality into a service .

module.factory('RecursionHelper', ['$compile', function($compile){
    return {
        /**
         * Manually compiles the element, fixing the recursion loop.
         * @param element
         * @param [link] A post-link function, or an object with function(s) registered via pre and post properties.
         * @returns An object containing the linking functions.
         */
        compile: function(element, link){
            // Normalize the link parameter
            if(angular.isFunction(link)){
                link = { post: link };
            }

            // Break the recursion loop by removing the contents
            var contents = element.contents().remove();
            var compiledContents;
            return {
                pre: (link && link.pre) ? link.pre : null,
                /**
                 * Compiles and re-adds the contents
                 */
                post: function(scope, element){
                    // Compile the contents
                    if(!compiledContents){
                        compiledContents = $compile(contents);
                    }
                    // Re-add the compiled contents to the element
                    compiledContents(scope, function(clone){
                        element.append(clone);
                    });

                    // Call the post-linking function, if any
                    if(link && link.post){
                        link.post.apply(null, arguments);
                    }
                }
            };
        }
    };
}]);

      



With this service, you can easily create a tree directive (or other recursive directives). Below is an example of a tree directive:

module.directive("tree", function(RecursionHelper) {
    return {
        restrict: "E",
        scope: {family: '='},
        template: 
            '<p>{{ family.name }}</p>'+
            '<ul>' + 
                '<li ng-repeat="child in family.children">' + 
                    '<tree family="child"></tree>' +
                '</li>' +
            '</ul>',
        compile: function(element) {
            return RecursionHelper.compile(element);
        }
    };
});

      

See this Plunker for a demo. I like this solution because:

  • You don't need a special directive that makes your html less clean.
  • The recursion logic is abstracted away from the RecursionHelper service, so you keep your directives clean.
+4


source


I think you need to pass the child node to the child directive (via the scope variable). In your example, the root is always taken and displayed over and over.



Or follow this example. The template logic is perfectly capable of displaying nested directives.

0


source







All Articles