Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AngularJS: manual $compile vs natural $compile over a recursive directive

I've tried to create my own recursive directive with AngularJS, wich calls itself to transform an object in a view with a pretty JSON format. Well, first I used a ng-include calling a script with the template, with a ng-if inside of it verifing if the current value was an object, if is, the template call itself.

I always think this is a ungly way to doind that, so I transform in a directive, much more simple.

More and less... Because I discover the world of recursive directives and found a lot of things, and most interesting. I even gave it a read in source code of Angular in github (I recommend you to read: https://github.com/angular/angular.js), with was a good things.

I searched so hard, and I thinkg I'm almost finding the awser that will cherish my heart! Because I learn a lot of new things and you guys, will help me.

Look my code in the link below: https://github.com/Daymannovaes/htmljs/blob/master/js/directives/recursiveDataTemplateDirective.js

my directive are: recursive-data-template="data", where data are an object. This directive will loop over the key and values of this object, and if the value was an object, will do this again. The condition are made with ng-if="isObject(value)".

Ok, my first problem was the infinite loop. I need to remove the content in the compile phase and then imperatively compile the content in the postLink phase. My question: ** Why the manual compile do not falls on the same problem of the infinite loop? **

I'm compiling the same content, no condition are made (if the if(!compiledContent) was removed, the infinite loop still not occurring), the diference (I think) are only they are maded in diferent place, but I wasn't able to find in internet someone who awser my question!

So, thank you! (if the link doesn't working, here are the important code):

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>
like image 754
daymannovaes Avatar asked Jun 09 '14 03:06

daymannovaes


1 Answers

I believe this excerpt from the official documentation is relevant to what you're asking:

Note: The compile function cannot handle directives that recursively use themselves in their own templates or compile functions. Compiling these directives results in an infinite loop and a stack overflow errors. This can be avoided by manually using $compile in the postLink function to imperatively compile a directive's template instead of relying on automatic template compilation via template or templateUrl declaration or manual compilation inside the compile function.

And going from the code you've provided, you've seem to have done what this note is suggesting - that is, manually compiling inside the function (postLink) you're returning for the compile property of your directive.

like image 180
miqh Avatar answered Oct 20 '22 11:10

miqh