Sophie McCarrell
Sophie McCarrell

Reputation: 2871

Angular Directive $compile not compiling inner directives

I'm trying to make a set of directives so i can repeat through a large list of data without creating many scopes, because the scopes take many seconds to clean up by Chrome's garbage collection.

The issue in my solution is that I call $compile in the for loop, yet the directive inside the $compile'd html isn't being evaluated for every iteration of the loop. it's only being evaluated at the end.

console.log output:

lscope.name:  jason app.js:20
lscope.name:  fred app.js:20
lscope.name:  anthony app.js:20
lscope.name:  balory app.js:20
[div, jquery: "2.1.1", constructor: function, selector: "", toArray: function, get: function…] app.js:25

lessif:  true 

Code:

app.controller('MainCtrl', function($scope) {
    $scope.names = ['jason', 'fred', 'anthony', 'balory'];
});

app.directive('scopelessRepeat', function($compile) {
  console.log('scopeless repeat called');
    return {
      transclude: 'element',
      restrict: "AE",
      scope: false,
      link: function (lscope, lelement, lattrs, lcontroller, ltransclude) {
        console.log('attrs: ', lattrs);
        var root = $('<div></div>');
        ltransclude(lscope, function(transHtml) {
          for(var i=0; i!=lscope[lattrs.items].length; ++i){
           lscope[lattrs.key] = lscope[lattrs.items][i];
           console.log('lscope.name: ', lscope.name);
           $compile(transHtml.contents())(lscope, function cloneFn(cloneHtml) {
            root.append(cloneHtml);
           });
          }
          console.log(root);
          lelement.after(root);
        });
      },
    };
  });
    app.directive('lessIf', function($compile) {
      return {
        transclude: 'element',
        restrict: "AE",
        scope: false,
        priority: 1000,
        //link: function (lscope, lelement, lattrs, lcontroller, ltransclude) {
        controller: function ($scope, $element, $attrs) {
          console.log('lessif: ', $scope.$eval($attrs['lessIf']));
          if($scope.$eval($attrs['lessIf']))
            $element.replaceWith($compile($element)($scope));
          else 
            $element.replaceWith(' ');      
        },        
      };      
    });

Why is my inner directive not being evaluated every iteration loop? (p.s. yes I know about bind-once, but it doesn't help the garbage collection issue, also the dev isn't getting back to me about have multiple contexts for a bind-once, so I have to roll my own)

Plnkr:

Upvotes: 0

Views: 282

Answers (1)

zs2020
zs2020

Reputation: 54543

Do it like this, you need to put the ltransclude(..) inside the loop.

for (var i = 0; i != lscope[lattrs.items].length; ++i) {
    ltransclude(lscope, function(transHtml) {

      lscope[lattrs.key] = lscope[lattrs.items][i];
      $compile(transHtml.contents())(lscope, function cloneFn(cloneHtml) {
        root.append(cloneHtml);
      });

      lelement.after(root);
    });
  }

Upvotes: 1

Related Questions