我的角度控制器中有一个函数,我希望这个函数可以在文档准备好的情况下运行但是我注意到角度在创建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
}
任何人都知道如何解决这个问题?
答案 0 :(得分:437)
我们可以使用angular.element(document).ready()
方法为文档准备好时附加回调。我们可以简单地在控制器中附加回调,如下所示:
angular.module('MyApp', [])
.controller('MyCtrl', [function() {
angular.element(document).ready(function () {
document.getElementById('msg').innerHTML = 'Hello';
});
}]);
答案 1 :(得分:28)
查看此帖子How to execute angular controller function on page load?
快速查找:
// 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
};
这样,您不必等到文档准备就绪。
答案 2 :(得分:22)
Angular会在
DOMContentLoaded
事件或何时自动初始化 如果当时是document.readyState,则会计算angular.js脚本 设置为“完成”。此时Angular会查找ng-app 指定应用程序根目录的指令。
https://docs.angularjs.org/guide/bootstrap
这意味着控制器代码将在DOM准备好后运行。
因此它只是$scope.init()
。
答案 3 :(得分:17)
Angular有几个时间点来开始执行函数。如果你寻找类似jQuery的东西
$(document).ready();
您可能会发现角度模拟非常有用:
$scope.$watch('$viewContentLoaded', function(){
//do something
});
当您想要操作DOM元素时,这个很有用。只有在加载了所有te元素后才会开始执行。
UPD:当您想要更改css属性时,上述内容有效。但是,当您想要测量元素属性(例如宽度,高度等)时,有时它不起作用。在这种情况下,您可能想尝试这样:
$scope.$watch('$viewContentLoaded',
function() {
$timeout(function() {
//do something
},0);
});
答案 4 :(得分:2)
我有类似的情况,我需要在加载视图后执行控制器功能,并且在视图中的特定第三方组件加载,初始化并在$ 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仍将是未定义的。
答案 5 :(得分:1)
这是我在使用coffeescript的外部控制器内部的尝试。它工作得很好。请注意,settings.screen.xs | sm | md | lg是我在app中包含的非uglified文件中定义的静态值。这些值是针对同名媒体查询大小的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()
答案 6 :(得分:1)
答案
$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()毫无用处,因为以角度构造的DOM可能还差得远。
但是更有趣的是,即使在$ viewContentLoaded被触发后,仍然找不到感兴趣的元素。
仅在执行$ timeout之后才发现它。请注意,即使$ timeout的值为0,执行前也要经过近200毫秒,这表明该线程被搁置了一段时间,大概是在DOM的主线程上添加了角度模板的情况下。从第一个$ document.ready()到最后一个$ timeout执行的总时间接近500毫秒。
在一种特殊情况下,先设置组件的值,然后在$ timeout中稍后更改text()值,则必须增加$ timeout值,直到它起作用为止(即使可以在执行期间找到该元素) $超时)。在第3方组件中发生异步操作导致值优先于文本,直到经过足够的时间为止。另一个可能是$ scope。$ evalAsync,但是没有尝试过。
我仍在寻找一个事件,该事件告诉我DOM已经完全解决,可以对其进行操作,以使所有情况都起作用。到目前为止,必须有一个任意的超时值,这意味着充其量只是在慢速浏览器上可能无法正常工作。我还没有尝试过像liveQuery和publish / subscribe这样的JQuery选项,这些选项可能有用,但肯定不是纯角度的。
答案 7 :(得分: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
});
});
}]);
答案 8 :(得分:0)
为什么不尝试提及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);
...
});
这对我有用。
答案 9 :(得分:0)
$scope.$on('$ViewData', function(event) {
//Your code.
});