Javascript 如何在文档就绪时在AngularJS控制器中运行函数?

Javascript 如何在文档就绪时在AngularJS控制器中运行函数?,javascript,angularjs,onload,Javascript,Angularjs,Onload,我的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 th

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

有人知道我该怎么做吗?

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

angular.module('MyApp', [])

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

Angular在
DOMContentLoaded
事件发生时或 如果此时document.readyState 设置为“完成”。此时Angular将查找ng应用程序 指定应用程序根目录的指令

这意味着控制器代码将在DOM就绪后运行

因此,它只是
$scope.init()
请参阅本文
要快速查找,请执行以下操作:

// 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
};
//在html中注册控制器
//内部控制器
$scope.init=函数(){
//检查url中是否有查询
//如果其值不为空,则进行火灾搜索
};

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

下面是我使用coffeescript在外部控制器内部进行的尝试。它相当有效。请注意,settings.screen.xs | sm | md | lg是在我随应用程序附带的非UGLIZED文件中定义的静态值。这些值是根据同名媒体查询大小的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()
xs=settings.screen.xs//480
sm=settings.screen.sm//768
md=settings.screen.md//992
lg=settings.screen.lg//1200
doMediaQuery=()->
w=角度.element($window).width()
$scope.xs=w=sm和w=md和w=lg
$scope.media=如果$scope.xs
“xs”
否则,如果$scope.sm
“sm”
如果$scope.md
“医学博士”
其他的
“lg”
$document.ready()->doMediaQuery()
元素($window).bind'resize',()->doMediaQuery()

我也遇到过类似的情况,在加载视图之后,以及在加载、初始化视图中的特定第三方组件并在$scope上放置对自身的引用之后,我需要执行控制器功能。最终对我有效的是在这个scope属性上设置一个watch,并在初始化之后启动我的函数

// $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();
您可能会发现这种角度模拟非常有用:

$scope.$watch('$viewContentLoaded', function(){
    //do something
});
当您想要操纵DOM元素时,这一点很有用。它将仅在加载所有te元素后开始执行

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

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

为什么不试试我所说的呢

元素(回调)

我在$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.
});
$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已经完全稳定下来,并且可以被操纵,以便所有案例都能正常工作。到目前为止,需要一个任意的超时值,这意味着充其量这是一个在速度较慢的浏览器上可能无法工作的混乱。我没有尝试过像liveQuery和publish/subscribe这样的JQuery选项,它们可能会起作用,但肯定不是纯角度的。

如果您得到类似于
getElementById调用返回null的结果,可能是因为函数正在运行,但ID没有时间加载到DOM中

试着延迟使用威尔的答案(朝上)。例如:

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
        });
    });
}]);

我试着这么做,但奇怪的是,它没有起作用。我的页面中的一些东西没有加载,如何知道在执行诸如单击按钮等操作之前它什么时候准备好。在编写aotomated web测试时?另外,
DOMContentLoaded
在文档完全加载和解析后启动,而不等待样式表,完成加载的图像和子帧。有关更多信息,请参阅。或者您可以使用$document.ready(function(){…}),Angular Docs:您需要注入
$document
才能使用它<代码>角度。元素
开箱即用。您将