261

我的角度控制器中有一个函数,我希望这个函数在准备好的文档上运行,但我注意到角度在创建 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
 }

有人知道我该怎么做吗?

4

10 回答 10

456

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

于 2013-09-05T22:13:14.410 回答
29

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

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

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

于 2014-10-16T07:02:11.747 回答
28

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

$(document).ready();

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

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

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

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

$scope.$watch('$viewContentLoaded', 
    function() { 
        $timeout(function() {
            //do something
        },0);    
});
于 2017-02-15T14:25:10.280 回答
22

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

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

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

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

于 2013-09-05T22:20:25.090 回答
4

答案

$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 期间可以找到该元素)。第 3 方组件中的某些异步导致值优先于文本,直到经过足够的时间。另一种可能性是 $scope.$evalAsync,但没有尝试过。

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

于 2018-06-20T18:04:40.043 回答
2

我有类似的情况,我需要在加载视图之后执行控制器功能,并且在加载、初始化视图中的特定 3rd 方组件并在 $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 仍然是未定义的。

于 2016-04-27T15:30:12.460 回答
1

这是我在使用咖啡脚本的外部控制器内部的尝试。它工作得很好。请注意,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()
于 2015-06-06T19:52:10.520 回答
1

如果你得到类似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
        });
    });
}]);
于 2019-01-11T16:05:56.803 回答
0

为什么不尝试使用 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);
        ...
    });

这对我有用。

于 2017-10-04T22:22:27.107 回答
0
$scope.$on('$ViewData', function(event) {
//Your code.
});
于 2018-02-23T06:56:11.313 回答