Angular 指令中的递归 [英] Recursion in Angular directives
问题描述
有几个流行的递归角度指令问答,它们都归结为以下解决方案之一:
There are a couple of popular recursive angular directive Q&A's out there, which all come down to one of the following solutions:
- 根据运行时范围状态手动增量编译"HTML
- manually incrementally 'compile' HTML based on runtime scope state
- example 1 [stackoverflow]
- example 2 [angular jsfiddles page]
第一个的问题是,除非您对手动编译过程进行了全面的管理,否则您无法删除以前编译的代码.第二种方法的问题是...不是指令并错过了其强大的功能,但更紧迫的是,它不能像指令一样参数化;它只是绑定到一个新的控制器实例.
The first one has the problem that you can't remove previously compiled code unless you comprehensibly manage the manual compile process. The second approach has the problem of... not being a directive and missing out on its powerful capabilities, but more urgently, it can't be parameterised the same way a directive can be; it's simply bound to a new controller instance.
我一直在尝试在链接函数中手动执行
angular.bootstrap
或@compile()
,但这给我留下了手动跟踪的问题要删除和添加的元素.I've been playing with manually doing an
angular.bootstrap
or@compile()
in the link function, but that leaves me with the problem of manually keeping track of elements to remove and add.有没有一种好的方法来管理添加/删除元素以反映运行时状态的参数化递归模式?也就是说,带有添加/删除节点按钮和一些输入字段的树,其值向下传递节点的子节点.也许是第二种方法与链式作用域的结合(但我不知道如何做到这一点)?
Is there a good way to have a parameterized recursive pattern that manages adding/removing elements to reflect runtime state? That is to say, a tree with a add/delete node button and some input field whose value is passed down a node's child nodes. Perhaps a combination of the second approach with chained scopes (but I have no idea how to do this)?
推荐答案
受到@dnc253 提到的线程中描述的解决方案的启发,我抽象了递归功能进入服务.
Inspired by the solutions described in the thread mentioned by @dnc253, I abstracted the recursion 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); } } }; } }; }]);
用法如下:
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.我最喜欢这个解决方案,因为:
See this Plunker for a demo. I like this solution best because:
- 你不需要一个特殊的指令来让你的 html 变得不那么干净.
- 递归逻辑被抽象到 RecursionHelper 服务中,因此您可以保持指令干净.
更新:从 Angular 1.5.x 开始,不再需要任何技巧,但仅适用于 template,不适用于 templateUrl
Update: As of Angular 1.5.x, no more tricks are required, but works only with template, not with templateUrl
这篇关于Angular 指令中的递归的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
- manually incrementally 'compile' HTML based on runtime scope state