DOM在指令的链接函数中没有准备好。 hacky超时是唯一的解决方案吗? [英] DOM is not ready in a directive's link function. Is hacky Timeout the only solution?

查看:98
本文介绍了DOM在指令的链接函数中没有准备好。 hacky超时是唯一的解决方案吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在指令模板中使用 ng-repeat

myApp.directive("test", function () {
    return {
   restrict: 'C',
     scope: {
      bindVar: '='
    },
        template: '<div>\
<div class="item" ng-repeat="sel in bindVar">{{sel.display}}</div>\
     </div>',
     link: function ($scope, element, attrs) {


     //   setTimeout(function() { 
        alert($('.item').length); // <--- RETURNS 0, IF I ADD TIMEOUT RETURNS 3
   // },0);



     } // of link
    } // of return
});

http://jsfiddle.net/foreyez/t4590zbr/

然而,当链接()函数我似乎无法访问已创建的项目。为了做到这一点,我需要将超时设置为0(之后它可以工作)。

However, when the link() function is called I don't seem to get access to the items that have been created. In order to do this I need to set a timeout of 0 (after that it works).

我在下面的文章中读到了这一点: http://lorenzmerdian.blogspot.com/2013/03/how -to-handle-dom-updates-in-angularjs.html

I read this in the following article: http://lorenzmerdian.blogspot.com/2013/03/how-to-handle-dom-updates-in-angularjs.html

我还看到了一个类似Stack Overflow的答案,其中OP标记了Timeout作为答案: 在AngularJS Directive的link()函数中未准备好DOM元素

I also saw a similar Stack Overflow answer where the OP marked Timeout as the answer: DOM elements not ready in AngularJS Directive's link() function

但是,来吧,还有另一种方式!

But c'mon, there's got to be another way!

我正在指责我这个hacky解决方案是错误的,并且有一些方法,当通过指令创建DOM时,angular提供回调。或者我真的依赖...超时? (真的?:/)

I'm crossing my fingers that this hacky solution is wrong, and there's some way that angular provides a callback when the DOM has been created via a directive. Or do I really rely on .. timeouts? (really? :/)

推荐答案

$ timeout 实际上是,当您使用内联模板(而不是 templateUrl )时,这是解决此问题的合法方法。它不会产生竞争条件。

$timeout is, in fact, a legitimate way to solve this when you use inline template (as opposed to templateUrl). It would not create a race condition.

会发生什么,Angular遍历DOM并收集指令及其前后链接函数(通过编译指令) 。然后,执行每个节点(即DOM元素)的每个指令的链接函数。

What happens is, Angular goes over the DOM and collects directives and their pre- and post-link functions (by compiling the directives). Then, the link functions for each directive for each node (i.e. DOM element) are executed.

通常,节点的模板(指令适用的模板)已经是DOM的一部分。所以,如果你有以下指令:

Normally, the template for the node (to which the directive applies) is already part of the DOM. And so, if you have the following directive:

.directive("foo", function(){
  return {
    template: '<span class="fooClass">foo</span>',
    link: function(scope, element){
      // prints "<span class="fooClass">foo</span>"
      console.log(element.html()); 
    }
  }
}

它可以找到 $(。fooClass)元素。

但是,如果指令使用 transclude:'element',例如 ng-if ngIf。 js )和 ng-repeat ngRepeat.js )指令,Angular将指令重写为注释( compile.js ),所以 $(。item)(在你的例子中)直到 ng-repeat 将它放在那里。他们在范围内这样做。$ watch function( ngIf.js ),取决于他们正在观看的值,这可能发生在下一个摘要周期。因此,即使您的后链接功能运行,您搜索的实际元素仍然不存在。

However, if a directive uses transclude: 'element', like ng-if (ngIf.js) and ng-repeat (ngRepeat.js) directives do, Angular rewrites the directive as a comment (compile.js), and so $(".item") (in your example) is not there until ng-repeat places it there. They do so in their scope.$watch function (ngIf.js), depending on the value they are watching, and this may happen at the next digest cycle. So, even when your post-link function runs, the actual element that you are search for is still not there.

.directive("foo", function(){
  return {
    template: '<span ng-if="true" class="fooClass">foo</span>',
    link: function(scope, element){
      // prints "<!-- ngIf: true -->"
      console.log(element.html());
    }
  }
}

成为肯定 - 当 $ timeout 运行时。

But it will be there - definitely - when $timeout runs.

这篇关于DOM在指令的链接函数中没有准备好。 hacky超时是唯一的解决方案吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆