javascript - Angular 指令中的递归

标签 javascript recursion angularjs

有几个流行的递归 Angular Directive(指令)问答,它们都归结为以下解决方案之一:

第一个的问题是,除非您全面管理手动编译过程,否则无法删除以前编译的代码。 第二种方法的问题是......不是指令并且错过了它强大的功能,但更紧迫的是,它不能像指令一样被参数化;它只是绑定(bind)到一个新的 Controller 实例。

我一直在尝试在链接函数中手动执行 angular.bootstrap@compile(),但这给我留下了手动跟踪的问题要删除和添加的元素。

有没有一种好方法可以使用参数化的递归模式来管理添加/删除元素以反射(reflect)运行时状态?也就是说,具有添加/删除节点按钮和一些输入字段的树,其值向下传递到节点的子节点。也许是第二种方法与链式作用域的结合(但我不知道该怎么做)?

最佳答案

受@dnc253 提到的线程中描述的解决方案的启发,我抽象了递归功能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", ["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);
        }
    };
}]);

查看 Plunker演示。 我最喜欢这个解决方案,因为:

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

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

关于javascript - Angular 指令中的递归,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14430655/

相关文章:

java - 如何使用递归实现dfs?

algorithm - 在列表中查找元素集,元素只能使用一次 - 如何处理算法

javascript - 包含指令的指令不使用指令范围,即使特别告知

javascript - 使用 $parse 的动态数组推送

javascript - Angular TypeError 无法读取未定义的属性 'then'

用于在文本区域中编码的 JavaScript 库(具有适当的缩进)

javascript - 暂时注释掉&lt;script&gt;标签,方便调试

javascript - 如何在 PhoneGap 的 windows 平台上实现 map (Google 或 Bing)?

javascript - 在某个事件发生后向 ng-repeat 中的元素添加一个类

haskell - 在 Haskell 中编写带条件的递归函数 :