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

IT技术 javascript angularjs onload
2021-01-23 00:47:22

我的 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
 }

有谁知道我该怎么做?

6个回答

我们可以使用该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/

您需要注入$document才能使用它。angular.element开箱即用。
2021-03-14 00:47:22
这对我不起作用,getElementById 调用返回 null。
2021-03-17 00:47:22
您需要注入 $document 才能使用它,但这是引用文档元素的推荐方式。您不必这样做,但它使测试变得更容易。
2021-03-26 00:47:22
document是一个全局变量,其中 as$document可以通过 angular 注入,从而使测试更容易。通常很难对访问全局 JS 变量(如文档或窗口)的应用程序进行单元测试。我也认为这module.run是放置此代码而不是控制器的好地方。
2021-03-26 00:47:22
或者你可以使用 $document.ready(function(){...}), Angular Docs: docs.angularjs.org/api/ng/service/$document
2021-03-27 00:47:22

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

// 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
};

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

如果我需要调用 after-page-load 怎么办?
2021-03-17 00:47:22

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

$(document).ready();

您可能会发现这个 angular 模拟非常有用:

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

当您想要操作 DOM 元素时,这会很有帮助。只有在加载所有 te 元素后,它才会开始执行。

UPD:当您想更改 css 属性时,上述内容有效。但是,有时当您要测量元素属性(例如宽度、高度等)时它不起作用。在这种情况下,您可能想尝试以下操作:

$scope.$watch('$viewContentLoaded', 
    function() { 
        $timeout(function() {
            //do something
        },0);    
});
它仅适用于 setTimeout (0) - 没有它,例如 ng-repeat 下的内容此时尚未加载
2021-04-01 00:47:22
这比建议的答案更值得。我在不使用 $timeout 的情况下完成了这项工作。
2021-04-12 00:47:22

DOMContentLoaded如果当时 document.readyState 设置为“完成”,Angular 会在发生事件或评估 angular.js 脚本时自动初始化此时,Angular 会查找指定应用程序根目录的 ng-app 指令。

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

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

因此它只是$scope.init().

我试图这样做,但奇怪的是它不起作用我的页面中的某些东西没有加载
2021-03-21 00:47:22
以及如何在编写自动化 Web 测试时在执行单击按钮等操作之前知道 Angular 代码何时准备就绪?
2021-04-10 00:47:22
此外DOMContentLoaded,当文件被完全加载和分析,而无需等待样式表,图片和完成加载子被激发。有关更多信息,请参阅DOMContentLoaded 和加载事件之间的区别是什么?.
2021-04-11 00:47:22

答案

$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 在主线程上添加了 angular 模板。从第一次 $document.ready() 到最后一次 $timeout 执行的总时间接近 500 毫秒。

在一种特殊情况下,设置了组件的值,然后在 $timeout 中稍后更改 text() 值,必须增加 $timeout 值直到它起作用(即使可以在 $timeout 期间找到该元素)。3rd 方组件中的一些异步导致值优先于文本,直到经过足够的时间。另一种可能性是 $scope.$evalAsync,但没有尝试过。

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