Angular 1.x - $ scope的顺序是怎么回事?

时间:2017-09-07 18:48:54

标签: javascript angularjs event-loop angular1.6

我有一个控制器,我需要使用ajax加载内容。当它正在加载时,我想要一个微调器出现在过渡期间。代码如下所示:

<i class="fa fa-2x fa-spin fa-spinner" ng-show="isLoadingContent"></i>

和相应的js:

$scope.isLoadingContent = true;
$q.all(promises).then(function (values) {
    $scope.isLoadingContent = false;
    // more code - display returned data

但是,当我单步执行代码时,微调器的UI不会出现在我希望它出现的位置。

$scope.isLoadingContent = true;
debugger; // the spinner does not appear on the UI
$q.all(promises).then(function (values) {
    debugger; // the spinner finally does appear in the UI at this point
    $scope.isLoadingContent = false;
    // more code - display returned data

我已经尝试逐步完成代码,但对于发生的事情做了简短的介绍 -  而且我确信我误解了事件循环中发生的事件序列以及角度循环在所有这些中发挥作用的地方。

是否有人能够解释为什么将微调器设置为在promise的方法中而不是我设置$scope.isLoadingContent的位置?是不是实际上已经设置了,而是在事件循环的消息队列中排队?

------------编辑------------

我相信我遇到了关于发生了什么的解释。非常感谢@jcford和@istrupin。

原帖中缺少一点点花絮,事件触发了promise调用,spinner更新实际上是基于$scope.$on("some-name", function(){...})事件 - 实际上是在当前控制器范围之外触发​​的click事件。我认为这意味着$ digest循环不会像通常那样工作,因为事件发起的位置被触发了。因此$on函数中的任何更新都不会像通常那样调用$ apply / $ digest,这意味着我必须专门进行$ digest调用。

奇怪的是,我现在意识到在$q.all()内,它必须调用$apply,因为在调试时,我看到了我所期望的DOM更改。 FWIW。

tl; dr - 致电$digest

3 个答案:

答案 0 :(得分:3)

这两个答案的组合将在这里完成。使用

$scope.$evalAsync()

这将以适当的方式将范围应用与超时结合起来。 $ evalAsync中的代码将包含在当前摘要中或等到当前摘要结束并开始使用您的更改的新摘要。

$q.all(promises).then(function (values) {
    $scope.$evalAsync($scope.isLoadingContent = false);
});

答案 1 :(得分:2)

在分配$scope.$apply()以强制摘要后尝试添加$scope.isLoadingContent = true。代码的其余部分可能会有一些内容阻止它立即应用。

正如许多评论中所指出的,这绝对是一种黑客行为,并不是解决问题的最佳方式。也就是说,如果这确实有效,您至少知道您的绑定设置正确,这将允许您进一步调试。既然你提到了它,那么接下来的步骤就是看看是什么搞了正常的摘要周期 - 比如用户JC Ford建议的在角度之外触发。

答案 2 :(得分:-2)

我通常使用isContentLoaded(作为isLoading的oposite)。我首先保留未定义,因此ng-show="!isContentLoaded"保证在第一次模板迭代时出现。

当加载all时,我将isContentLoaded设置为true。

要调试模板,您需要使用$ timeout $timeout(function () { debugger; }) 这将在第一个摘要周期后立即停止代码执行,并且所有$ scope变量值都反映在DOM中。