DOM在指令的链接函数中没有准备好。 hacky超时是唯一的解决方案吗? [英] DOM is not ready in a directive's link function. Is hacky Timeout the only solution?
问题描述
我在指令模板中使用 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/
然而,当链接()调用code>函数我似乎无法访问已创建的项目。为了做到这一点,我需要将超时设置为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屋!