Why is the content of an ng-include dynamically loaded template not available via DOM selectors?

StackOverflow https://stackoverflow.com/questions/17505484

  •  02-06-2022
  •  | 
  •  

Question

Here's a jsfiddle showing the problem: http://jsfiddle.net/yRLKe/5/

One button compiles before injecting to the DOM, the other one injects before compiling. I did both to make sure that how I compile wasn't the cause of the problem.

Whichever button you click, check the console output and you'll see that the actual template's contents are not available when selecting from the DOM.

So the question is firstly why? - why does it behave this way? but most importantly how? - how can I get access to the actual loaded template's HTML via DOM selectors?

Here's the template:

<script type="text/ng-template" id="template1.html">
   <div>This is template 1!</div>
   <div id="test">Hello {{name}}</div>
</script>

Here's the controller:

myApp.controller('MyCtrl', function($scope) {
  $scope.name = 'Superhero';
  $scope.template = {url:'template1.html'};
  $scope.clickButton1 = function(){
    $scope.$emit('buttonClicked1');  
  };
  $scope.clickButton2 = function(){
    $scope.$emit('buttonClicked2');  
  };
});

Here's the directive:

myApp.directive('compileBeforeInsert', function($compile){
  return function(scope, element, attrs){
    scope.$on('buttonClicked1',function(ev){
        var container = $('#container');
        container.html('<div ng-include src="template.url" id="template">test1</div>');
        $compile(container)(scope);
        console.log('before');
        console.log($('#template').html());
    });    
  }
});

This directive outputs "test1" to the console whereas I would expect it to output "Hello Superman!".

Was it helpful?

Solution

The dom is not rendered when the output is written to the console. Using $timeout, you can view the rendered content. MANY people say this is a hack. Regardless, it works. Here's what I changed, with the same result in both directives:

//after injecting $timeout in the directive:
  $compile(container)(scope);
  console.log('before');
  console.log($('#template').children().text());
  $timeout(function(){
      console.log('before, in timeout:');
      console.log($('#template').children().text());
  },0)

Here's the fiddle

Also, see this answer and check out the links within.

OTHER TIPS

Your compileBeforeInsert definitely can't work, since you're calling compile -> link -> element but doing nothing with the returned element. It's a no-op.

As to why compileAfterInsert doesn't work, I believe that ng-include is always async, even if the content is already locally available. That's why rgill's setTimeout works.

You might want to re-think this approach... the idea of Angular is that it keeps compiling and digesting over and over until things eventually end up in their stable end state. And there may be asynchronous breaks in that path.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top