我在我的angular控制器中有一个函数,我希望这个函数在文档就绪时运行,但我注意到angular在创建dom时运行它。
function myController($scope)
{
$scope.init = function()
{
// I'd like to run this on document ready
}
$scope.init(); // doesn't work, loads my init before the page has completely loaded
}
有人知道我该怎么做吗?
我有一个类似的情况,我需要在视图加载后执行一个控制器函数,也在视图中特定的第三方组件被加载,初始化,并在$scope上放置了对自身的引用。最终对我有用的是在这个scope属性上设置一个手表,并在初始化后才启动我的函数。
// $scope.myGrid property will be created by the grid itself
// The grid will have a loadedRows property once initialized
$scope.$watch('myGrid', function(newValue, oldValue) {
if (newValue && newValue.loadedRows && !oldValue) {
initializeAllTheGridThings();
}
});
使用未定义的值调用监视程序几次。然后,当网格创建并具有预期的属性时,可以安全地调用初始化函数。第一次使用非未定义的newValue调用观察者时,oldValue仍然是未定义的。
Angular有几个开始执行函数的时间点。如果您正在寻找类似jQuery的
$(document).ready();
你可能会发现这个类比在angular中非常有用:
$scope.$watch('$viewContentLoaded', function(){
//do something
});
当您想要操作DOM元素时,这个选项非常有用。它只在所有te元素加载后才开始执行。
UPD:当你想改变css属性时,上面所说的是有效的。然而,当您想测量元素属性(如宽度、高度等)时,有时它就不起作用了。在这种情况下,你可能想试试这个:
$scope.$watch('$viewContentLoaded',
function() {
$timeout(function() {
//do something
},0);
});
这个问题的答案
$scope.$watch('$viewContentLoaded',
function() {
$timeout(function() {
//do something
},0);
});
是唯一一个在我测试的大多数情况下都有效的方法。在一个包含4个组件的示例页面中,所有组件都从一个模板构建HTML,事件的顺序为
$document ready
$onInit
$postLink
(and these 3 were repeated 3 more times in the same order for the other 3 components)
$viewContentLoaded (repeated 3 more times)
$timeout execution (repeated 3 more times)
所以$document.ready()在大多数情况下是无用的,因为在angular中构造的DOM可能还远没有准备好。
但更有趣的是,即使在$viewContentLoaded触发后,仍然无法找到感兴趣的元素。
只有在执行$timeout之后才找到它。请注意,尽管$timeout的值为0,但在它执行之前已经经过了近200毫秒,这表明该线程被暂停了相当长一段时间,可能是因为DOM在主线程中添加了角模板。从第一个$document.ready()到最后一个$timeout执行的总时间将近500毫秒。
在一个特殊的情况下,设置了组件的值,然后在$timeout期间更改了text()值,$timeout值必须增加,直到它工作为止(即使在$timeout期间可以找到该元素)。第三方组件中的某些异步操作导致值优先于文本,直到足够的时间过去。另一种可能是$scope。$evalAsync,但是没有尝试。
我仍然在寻找这样一个事件,它告诉我DOM已经完全稳定下来,并且可以对其进行操作,以便所有的用例都能正常工作。到目前为止,任意的超时值是必要的,这意味着这充其量是一个拼凑,可能无法在缓慢的浏览器上工作。我还没有尝试过JQuery的选项,比如liveQuery和publish/subscribe,它们可能有用,但肯定不是纯angular的。