我发现自从在angular中构建应用程序以来,我越来越需要手动将页面更新到我的范围。
我知道的唯一方法是从控制器和指令的范围调用$apply()。这样做的问题是,它不断向控制台抛出一个错误,错误如下:
错误:$digest已在进行中
有人知道如何避免这种错误或以不同的方式实现相同的事情吗?
我发现自从在angular中构建应用程序以来,我越来越需要手动将页面更新到我的范围。
我知道的唯一方法是从控制器和指令的范围调用$apply()。这样做的问题是,它不断向控制台抛出一个错误,错误如下:
错误:$digest已在进行中
有人知道如何避免这种错误或以不同的方式实现相同的事情吗?
当前回答
我对第三方脚本也有同样的问题,比如CodeMirror和Krpano,甚至使用这里提到的safeApply方法也没有为我解决错误。
但解决这个问题的方法是使用$timeout服务(不要忘记先注入它)。
因此,类似于:
$timeout(function() {
// run my code safely here
})
如果在代码中使用
这
也许是因为它在工厂指令的控制器内,或者只是需要某种绑定,那么您可以执行以下操作:
.factory('myClass', [
'$timeout',
function($timeout) {
var myClass = function() {};
myClass.prototype.surprise = function() {
// Do something suprising! :D
};
myClass.prototype.beAmazing = function() {
// Here 'this' referes to the current instance of myClass
$timeout(angular.bind(this, function() {
// Run my code safely here and this is not undefined but
// the same as outside of this anonymous function
this.surprise();
}));
}
return new myClass();
}]
)
其他回答
找到此:https://coderwall.com/p/ngisma其中Nathan Walker(靠近页面底部)建议在$rootScope中使用decorator来创建func“safeApply”,代码:
yourAwesomeModule.config([
'$provide', function($provide) {
return $provide.decorator('$rootScope', [
'$delegate', function($delegate) {
$delegate.safeApply = function(fn) {
var phase = $delegate.$$phase;
if (phase === "$apply" || phase === "$digest") {
if (fn && typeof fn === 'function') {
fn();
}
} else {
$delegate.$apply(fn);
}
};
return $delegate;
}
]);
}
]);
在为我们创建一个可重用的$safeApply函数方面,yearmomo做得很好:
https://github.com/yearofmoo/AngularJS-Scope.SafeApply
用法:
//use by itself
$scope.$safeApply();
//tell it which scope to update
$scope.$safeApply($scope);
$scope.$safeApply($anotherScope);
//pass in an update function that gets called when the digest is going on...
$scope.$safeApply(function() {
});
//pass in both a scope and a function
$scope.$safeApply($anotherScope,function() {
});
//call it on the rootScope
$rootScope.$safeApply();
$rootScope.$safeApply($rootScope);
$rootScope.$safeApply($scope);
$rootScope.$safeApply($scope, fn);
$rootScope.$safeApply(fn);
摘要周期是一个同步调用。在完成之前,它不会将控制权交给浏览器的事件循环。有几种方法可以解决这个问题。处理此问题的最简单方法是使用内置的$timeout,第二种方法是如果您使用下划线或lodash(您应该使用),请调用以下命令:
$timeout(function(){
//any code in here will automatically have an apply run afterwards
});
或者如果你有lodash:
_.defer(function(){$scope.$apply();});
我们尝试了几种变通方法,我们讨厌将$rootScope注入所有控制器、指令,甚至一些工厂。因此,到目前为止,$timeout和_.defer一直是我们的最爱。这些方法成功地告诉angular等待下一个动画循环,这将保证当前范围$申请已结束。
安全$apply的最短形式是:
$timeout(angular.noop)
如果你这样做,有时你仍然会出错(https://stackoverflow.com/a/12859093/801426).
试试看:
if(! $rootScope.$root.$$phase) {
...