Почему содержимое динамически загружаемого шаблона ng-include недоступно через селекторы DOM?

Вот jsfiddle, показывающий проблему: http://jsfiddle.net/yRLKe/5/

Одна кнопка компилируется перед внедрением в DOM, другая — перед компиляцией. Я сделал и то, и другое, чтобы убедиться, что способ компиляции не был причиной проблемы.

Какую бы кнопку вы ни нажали, проверьте вывод консоли, и вы увидите, что фактическое содержимое шаблона недоступно при выборе из DOM.

Итак, вопрос, во-первых, почему? - почему так себя ведет? но самое главное как? - как я могу получить доступ к HTML-коду фактического загруженного шаблона через селекторы DOM?

Вот шаблон:

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

Вот контроллер:

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');  
  };
});

Вот директива:

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());
    });    
  }
});

Эта директива выводит «test1» на консоль, тогда как я ожидал, что она выведет «Hello Superman!».


person geoidesic    schedule 06.07.2013    source источник
comment
Я получаю этот ответ: Это шаблон1! Привет Супергерой. какой у тебя браузер?   -  person Ron    schedule 06.07.2013
comment
Рон, ты уверен, что получаешь этот ответ в консоли? Я использую Хром.   -  person geoidesic    schedule 07.07.2013


Ответы (2)


Дом не отображается, когда вывод записывается на консоль. Используя $timeout, вы можете просматривать отображаемый контент. МНОГИЕ люди говорят, что это взлом. Несмотря ни на что, это работает. Вот что я изменил с тем же результатом в обеих директивах:

//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)

Вот скрипка

Кроме того, см. этот ответ и ознакомьтесь со ссылками внутри.

person rGil    schedule 06.07.2013
comment
Ok. Кажется, работает. Однако время ожидания зависит от скорости рендеринга браузера, поэтому я думаю, что это может быть ненадежным. Вряд ли это похоже на готовое к производству решение. - person geoidesic; 07.07.2013
comment
По сути, он просто добавляет завернутые объекты в конец очереди браузера. Так что даже задержка в 0 мс, как в этом примере, работает нормально. Как я уже сказал, многие говорят, что это хак и нарушает намерения angular. Как предполагает @darkporter, возможно, есть лучшее решение, которое зависит не от фактического рендеринга dom, а скорее от состояния модели. Просто зависит от реальной потребности использования. - person rGil; 07.07.2013

Ваш compileBeforeInsert определенно не может работать, так как вы вызываете compile -> link -> element, но ничего не делаете с возвращенным элементом. Это не работает.

Что касается того, почему compileAfterInsert не работает, я считаю, что ng-include всегда асинхронный, даже если контент уже доступен локально. Вот почему setTimeout работает.

Возможно, вы захотите переосмыслить этот подход... идея Angular заключается в том, что он продолжает компилировать и обрабатывать снова и снова, пока все в конечном итоге не окажется в стабильном конечном состоянии. И на этом пути могут быть асинхронные разрывы.

person jpsimons    schedule 06.07.2013
comment
Thx darkporter .. Я не уверен, что понимаю, что вы говорите. Я также не думаю, что это действительно отвечает на важный вопрос: как я могу получить доступ к шаблону в DOM после его внедрения? - person geoidesic; 07.07.2013
comment
Кто или что такое ргилл? Что вы имеете в виду, когда говорите, что вызываете элемент compile-›link-›, но ничего не делаете с возвращенным элементом? - person geoidesic; 07.07.2013