AngularJS:手动$ compile vs自然$ compile通过递归指令

时间:2014-06-09 03:38:33

标签: angularjs recursion compilation directive

我试图用AngularJS创建我自己的递归指令,它自称用一个漂亮的JSON格式转换视图中的对象。好吧,首先我使用了一个ng-include用模板调用脚本,在其中使用ng-if验证当前值是否是一个对象,如果是,模板调用本身。

我一直认为这是一种不可思议的方式,因此我在指令中进行转换,更为简单。

越来越少......因为我发现了递归指令的世界并发现了很多东西,而且最有趣。我甚至在github上给它读了Angular的源代码(我建议你阅读:https://github.com/angular/angular.js),这是件好事。

我搜索得如此努力,我想我几乎找到了能够珍惜我的心灵!因为我学到了很多新东西,你们会帮助我。

在下面的链接中查看我的代码:https://github.com/Daymannovaes/htmljs/blob/master/js/directives/recursiveDataTemplateDirective.js

我的指令是:recursive-data-template =" data",其中data是一个对象。该指令将遍历此对象的键和值,如果值是对象,则将再次执行此操作。条件是使用ng-if =" isObject(value)"。

好的,我的第一个问题是无限循环。我需要在编译阶段删除内容,然后在postLink阶段强制编译内容。我的问题: **为什么手动编译不会出现无限循环的同一问题? **

我正在编译相同的内容,没有条件(如果if(!compiledContent)被删除,无限循环仍未发生),差异(我认为)只是他们在不同的地方进行编组,但我无法在互联网上找到一个能够回答我问题的人!

所以,谢谢! (如果链接不起作用,这里是重要的代码):

compile: function(templateElement, templateAttributes) {
            /*
              in compile time, we need to remove the innerHTML of template(url) because of its recursive.
              Because of its recusiveness, when the $compile start to read the DOM tree and find a
              recursiveDataTemplate directive (even its not will be evaluated all time by link function
              because the ng-if, whatever) its start the do all the process again. So, we need the .remove()
             */
            var templateDirectiveContent = templateElement.contents().remove();
            var compiledContent;

            return function($scope, linkElement, linkAttributes) {

                /* 
                  This verification avoid to compile the content to all siblings, because
                  when you compile the siblings, don't work (I don't know why, yet).
                  So, doing this we get only the top level link function (from each iteration)
                 */
                if(!compiledContent) {
                    compiledContent = $compile(templateDirectiveContent);
                }

                /*
                  Calling the link function passing the actual scope we get a clone object
                  wich contains the finish viewed object, the view itself, the DOM!!
                  Then, we attach the new dom in the element wich contains the directive
                 */
                compiledContent($scope, function(clone) {
                  linkElement.append(clone); 
                });
            };
        },
  }
<ul>
    <li data-ng-repeat="(key, value) in fields">
        <span data-ng-if="!isNumber(key)">
            {{key}}:
        </span>

        <span data-ng-if="isObject(value)" recursive-data-template="value"></span>

        <span data-ng-if="!isObject(value)">
            {{value}}
        </span>

    </li>
</ul>

2 个答案:

答案 0 :(得分:1)

我相信 official documentation 的摘录与您提出的问题相关:

  

注意:编译函数无法处理在自己的模板或编译函数中递归使用自身的指令。编译这些指令会导致无限循环和堆栈溢出错误。这可以通过在$compile函数中手动使用postLink来强制编译指令的模板而不是通过templatetemplateUrl声明或手动编译依赖于自动模板编译来避免编译功能。

从您提供的代码开始,您似乎完成了本说明所建议的内容 - 也就是说,在函数内部手动编译(postLink),您将返回compile属性你的指示。

答案 1 :(得分:0)

关于在postLink而不是compile阶段进行编译的原因是为了避免无限递归,这是因为DOM的所有元素都是在实际使用或不使用的情况下编译的,而{只有当元素实际链接时才会触发{1}}:如果更高的link是伪造的,那么它的子元素将不会被预先链接,因此neithr postLinked ...至少从我的理解来看! / p>

我推荐这篇好文章:http://www.jvandemo.com/the-nitty-gritty-of-compile-and-link-functions-inside-angularjs-directives/