一尘不染

Angular指令中的递归

angularjs

有一些流行的递归角度指令Q&A,它们都归结为以下解决方案之一:

  • 根据运行时范围状态手动增量“编译” HTML
  • 完全不使用指令,而是引用自身的

    共1个答案

    一尘不染

    受@dnc253提到的线程中描述的解决方案的启发,我将递归功能抽象为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", ["RecursionHelper", 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) {
                // Use the compile function from the RecursionHelper,
                // And return the linking function(s) which it returns
                return RecursionHelper.compile(element);
            }
        };
    }]);
    

    看到这个柱塞的演示。我最喜欢此解决方案,因为:

    1. 您不需要特殊的指令,这会使您的html不太干净。
    2. 递归逻辑被抽象到RecursionHelper服务中,因此您可以保持指令整洁。

    更新:从Angular 1.5.x开始,不再需要其他技巧,但仅适用于 template ,不适用于 templateUrl

    2020-07-04