angularjs中的递归嵌套指令

时间:2014-08-04 13:39:31

标签: javascript angularjs recursion

我试图在angularjs中实现一个递归嵌套的指令。

我只是制作了一个<tree-dir>指令并获得了此jsFiddle

在我的tree_item_renderer.html模板中,如果我将ng-include替换为<tree-dir>,则在编译时,angular将进入无限循环(如果您尝试它会小心,它会减慢或停止浏览器一段时间。)

来源:this question关于角度的递归树。

2 个答案:

答案 0 :(得分:4)

This answer解释并解决了所有问题,以下是最重要的部分:

&#34;在进行树视图时,最佳解决方案是递归指令。但是,当你做出这样的指令时,你会发现AngularJS进入无限循环。

解决方法是让指令在编译事件期间删​​除元素,并手动编译并在链接事件中添加它们。

我在this thread中发现了这一点,并抽象了这个功能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);
                    }
                }
            };
        }
    };
}]);

使用此服务,您可以轻松制作树指令(或其他递归指令)。以下是树指令的示例:

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);
        }
    };
});

有关演示,请参阅此Plunker。我最喜欢这个解决方案,因为:

  1. 您不需要特殊的指令,这会使您的HTML不那么干净。
  2. 递归逻辑被抽象到RecursionHelper服务中,因此您可以保持指令清洁。&#34;

答案 1 :(得分:0)

我认为您需要将子节点传递给子指令(通过范围变量)。在您的示例中,始终会对根进行一次又一次的渲染。

或按照this示例操作。模板逻辑完全能够呈现嵌套指令。