如何在准备好文档的AngularJS控制器中运行函数



我的角度控制器中有一个函数,我希望这个函数在文档就绪时运行,但我注意到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
}

有人知道我该怎么做吗?

我们可以使用angular.element(document).ready()方法来附加文档准备就绪时的回调。我们可以简单地在控制器中附加回调,如下所示:

angular.module('MyApp', [])
.controller('MyCtrl', [function() {
angular.element(document).ready(function () {
document.getElementById('msg').innerHTML = 'Hello';
});
}]);

http://jsfiddle.net/jgentes/stwyvq38/1/

请参阅本文如何在页面加载时执行角度控制器功能?
快速查找:

// register controller in html
<div data-ng-controller="myCtrl" data-ng-init="init()"></div>
// in controller
$scope.init = function () {
// check if there is query in url
// and fire search in case its value is not empty
};

这样,您就不必等到文档准备好了。

Angular有几个时间点来开始执行函数。如果你在寻找类似jQuery的

$(document).ready();

你可能会发现这种角度模拟非常有用:

$scope.$watch('$viewContentLoaded', function(){
//do something
});

当您想要操作DOM元素时,这个非常有用。只有在加载完所有te元素后,它才会开始执行。

UPD:当你想更改css属性时,上面所说的有效。然而,当你想测量元素属性时,有时它不起作用,比如宽度、高度等。在这种情况下,你可能想试试这个:

$scope.$watch('$viewContentLoaded', 
function() { 
$timeout(function() {
//do something
},0);    
});

DOMContentLoaded事件或如果当时document.readyState设置为"完成"。此时Angular正在寻找ng应用程序指定应用程序根的指令。

https://docs.angularjs.org/guide/bootstrap

这意味着控制器代码将在DOM准备好之后运行。

因此它只是$scope.init()

答案

$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毫秒。

在一个特殊的情况下,组件的值被设置,然后text()值在$timeout中被更改,$timeout值必须增加,直到它工作为止(即使在$timeouth期间可以找到元素)。第三方组件中的异步导致一个值优先于文本,直到经过足够的时间。另一种可能性是$scope$evalAsync,但未尝试。

我仍在寻找一个事件,它告诉我DOM已经完全稳定下来,并且可以被操纵,以便所有案例都能工作。到目前为止,任意的超时值是必要的,这意味着这充其量是一个在慢速浏览器上可能不起作用的拼凑。我还没有尝试过像liveQuery和发布/订阅这样的JQuery选项,它们可能有效,但肯定不是纯粹的角度。

我也遇到过类似的情况,在加载视图后,以及在加载、初始化视图中的特定第三方组件并在$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仍将是未定义的。

下面是我使用coffeescript在外部控制器内部进行的尝试。它相当好用。请注意,settings.screen.xs|sm|md|lg是在应用程序中包含的未经验证的文件中定义的静态值。这些值是根据Bootstrap的同名媒体查询大小的3个官方断点:

xs = settings.screen.xs // 480
sm = settings.screen.sm // 768
md = settings.screen.md // 992
lg = settings.screen.lg // 1200
doMediaQuery = () ->
w = angular.element($window).width()
$scope.xs = w < sm
$scope.sm = w >= sm and w < md
$scope.md = w >= md and w < lg
$scope.lg = w >= lg
$scope.media =  if $scope.xs 
"xs" 
else if $scope.sm
"sm"
else if $scope.md 
"md"
else 
"lg"
$document.ready () -> doMediaQuery()
angular.element($window).bind 'resize', () -> doMediaQuery()

如果得到类似getElementById call returns null的东西,可能是因为函数正在运行,但ID还没有时间加载到DOM中。

试着延迟使用Will的答案(朝上)。示例:

angular.module('MyApp', [])
.controller('MyCtrl', [function() {
$scope.sleep = (time) => {
return new Promise((resolve) => setTimeout(resolve, time));
};
angular.element(document).ready(function () {
$scope.sleep(500).then(() => {        
//code to run here after the delay
});
});
}]);

为什么不试试angular文档提到的内容https://docs.angularjs.org/api/ng/function/angular.element.

angular.element(回调)

我在$onInit(){…}函数中使用过这个。

var self = this;
angular.element(function () {
var target = document.getElementsByClassName('unitSortingModule');
target[0].addEventListener("touchstart", self.touchHandler, false);
...
});

这对我有效。

$scope.$on('$ViewData', function(event) {
//Your code.
});

最新更新