我发现自从在angular中构建应用程序以来,我越来越需要手动将页面更新到我的范围。

我知道的唯一方法是从控制器和指令的范围调用$apply()。这样做的问题是,它不断向控制台抛出一个错误,错误如下:

错误:$digest已在进行中

有人知道如何避免这种错误或以不同的方式实现相同的事情吗?


当前回答

了解到Angular文档将检查$$阶段称为反模式,我尝试使用$timeout和_.deffer来工作。

超时和延迟方法在dom中创建一个未解析的{{myVar}}内容的闪存,就像FOUT一样。对我来说,这是不可接受的。这让我没有太多教条地告诉我,有些东西是黑客,没有合适的选择。

每次唯一有效的方法是:

if(scope.$$phase!==“$digest”){scope.$digest()}。

我不明白这种方法的危险性,也不明白为什么评论中的人和棱角分明的团队会把它描述为黑客。命令看起来很精确,很容易理解:

“做摘要,除非已经发生了”

在CoffeeScript中,它更漂亮:

范围$digest(),除非作用域$$阶段为“$digest”

这有什么问题?有没有替代方案不会产生FOUT$safeApply看起来不错,但也使用$$阶段检查方法。

其他回答

当您收到此错误时,基本上意味着它已经在更新视图的过程中。您真的不需要在控制器中调用$apply()。如果您的视图没有按预期进行更新,并且在调用$apply()后出现此错误,那么很可能意味着您没有正确更新模型。如果你发布一些细节,我们可以找出核心问题。

您可以使用$timeout来防止错误。

$timeout(function () {
    var scope = angular.element($("#myController")).scope();
    scope.myMethod(); 
    scope.$scope();
}, 1);

当我们要求angular运行摘要循环时,问题基本上就要出现了,尽管它正在进行中,这对angular的理解造成了问题。控制台中的结果异常。1.调用范围没有任何意义$$timeout函数中的apply(),因为在内部它也会这样做。2.该代码使用普通JavaScript函数,因为它的本机非角度定义,即setTimeout3.要做到这一点,你可以利用if(!scope.$$phase){范围$evalAsync(函数){});}

不要使用这种模式-这将导致比它解决的错误更多的错误。即使你认为它修复了一些东西,但它没有。

您可以通过检查$scope来检查$digest是否已在进行中$$阶段

if(!$scope.$$phase) {
  //$digest or $apply
}

$范围$$如果正在进行$digest或$apply,则阶段将返回“$digest”或“$apply”。我认为这些状态之间的区别在于,$digest将处理当前范围及其子范围的监视,而$apply将处理所有范围的监视。

就@dnc253而言,如果你发现自己经常调用$digest或$apply,那么你可能做得不对。我通常发现,当我需要更新作用域的状态时,我需要进行消化,因为DOM事件超出Angular的范围。例如,当twitter引导模式变为隐藏时。有时,当$digest正在进行时,DOM事件会触发,有时则不会。这就是我用这张支票的原因。

如果有人知道,我很想知道更好的方法。


来自评论:作者@anddoutoi

angular.js反模式

不执行if(!$scope.$$phase)$scope$apply(),表示$scope$apply()在调用堆栈中不够高。

我对第三方脚本也有同样的问题,比如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();

  }]
)