2

我有一个控制器,我需要使用 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

我曾尝试单步执行代码,但对正在发生的事情一无所知——而且我确信我误解了事件循环中发生的事件顺序以及角循环在所有这些中的作用。

是否有人能够解释为什么将微调器设置为出现在承诺的方法中而不是我设置的位置$scope.isLoadingContent?它实际上并没有被设置,而是在事件循环的消息队列中排队?

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

我相信我遇到了关于发生了什么的解释。很大程度上要感谢@jcford 和@istrupin。

所以原始帖子中缺少一点花絮,触发承诺调用的事件和微调器更新实际上是基于一个$scope.$on("some-name", function(){...})事件 - 实际上是在我当前控制器范围之外触发​​的点击事件。我相信这意味着 $digest 循环不像通常那样工作,因为事件起源是在哪里触发的。因此,函数中的任何更新$on都不会像通常那样调用 $apply/$digest,这意味着我必须专门进行 $digest 调用。

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

tl;博士-打电话$digest

4

3 回答 3

3

这两个答案的组合将在这里解决问题。利用

$scope.$evalAsync()

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

IE

$q.all(promises).then(function (values) {
    $scope.$evalAsync($scope.isLoadingContent = false);
});
于 2017-09-07T19:16:58.483 回答
2

$scope.$apply()在分配后尝试添加$scope.isLoadingContent = true以强制摘要。您的其余代码中可能存在某些内容使其无法立即应用。

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

于 2017-09-07T18:55:05.837 回答
-2

我通常使用 isContentLoaded(与 isLoading 相对)。我一开始没有定义它,所以ng-show="!isContentLoaded"保证在第一次模板迭代时出现。

全部加载后,我将 isContentLoaded 设置为 true。

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

于 2017-09-07T18:58:08.050 回答