我发现自从以角度构建应用程序后,我需要手动将页面更新到我的范围。
我知道这样做的唯一方法是从我的控制器和指令的范围调用$apply()
。这个问题是它不断向控制台抛出一个错误:
错误:$ digest 已在进行中
有谁知道如何避免这个错误或以不同的方式实现相同的事情?
不要使用这种模式 - 这最终会导致比它解决的更多错误。即使你认为它固定了一些东西,它也没有。
您可以通过检查$scope.$$phase
来检查$scope.$$phase
$digest
是否已在进行中。
if(!$scope.$$phase) {
//$digest or $apply
}
如果$digest
或$apply
正在进行中, $scope.$$phase
将返回"$digest"
或"$apply"
。我相信这些状态之间的区别在于$digest
将处理当前范围及其子项的监视, $apply
将处理所有范围的观察者。
对于 @ dnc253 来说,如果你发现自己经常叫$digest
或$apply
,你可能做错了。我通常发现当需要更新范围的状态时,我需要消化,因为 DOM 事件在 Angular 的范围之外触发。例如,当 twitter 引导模式变为隐藏时。有时,当$digest
正在进行时,DOM 事件会触发,有时则不会。这就是我使用这张支票的原因。
如果有人知道,我很想知道一个更好的方法。
来自评论:@anddoutoi
- 不要做
if (!$scope.$$phase) $scope.$apply()
,这意味着你的$scope.$apply()
在调用堆栈中不够高。
最近与 Angular 人就这个话题进行了讨论: 出于面向未来的原因,你不应该使用$$phase
当按下 “正确” 方式时,答案是当前的
$timeout(function() {
// anything you want can go here and will safely be run on the next digest.
})
我最近在编写角度服务时遇到了这个问题,以包装 facebook,google 和 twitter API,这些 API 在不同程度上都有回调。
这是服务中的一个例子。 (为了简洁起见,服务的其余部分 - 设置变量,注入 $ timeout 等 - 已被取消。)
window.gapi.client.load('oauth2', 'v2', function() {
var request = window.gapi.client.oauth2.userinfo.get();
request.execute(function(response) {
// This happens outside of angular land, so wrap it in a timeout
// with an implied apply and blammo, we're in action.
$timeout(function() {
if(typeof(response['error']) !== 'undefined'){
// If the google api sent us an error, reject the promise.
deferred.reject(response);
}else{
// Resolve the promise with the whole response if ok.
deferred.resolve(response);
}
});
});
});
请注意,$ timeout 的 delay 参数是可选的,如果未设置则默认为 0( $ timeout调用$ browser.defer , 如果未设置延迟,则默认为 0 )
有点不直观,但这是写 Angular 的人的答案,所以这对我来说已经足够了!
摘要周期是同步调用。在完成之前,它不会控制浏览器的事件循环。有几种方法可以解决这个问题。解决这个问题最简单的方法是使用内置的 $ timeout,第二种方法是使用下划线或 lodash(你应该这样),请调用以下内容:
$timeout(function(){
//any code in here will automatically have an apply run afterwards
});
或者如果你有下划线:
_.defer(function(){$scope.$apply();});
我们尝试了几种解决方法,我们讨厌将 $ rootScope 注入我们的所有控制器,指令甚至一些工厂。所以,到目前为止,$ timeout 和_.defer 一直是我们的最爱。这些方法成功地告诉 angular 等待下一个动画循环,这将保证当前范围。$ apply 结束。