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

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

错误:$digest已在进行中

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


当前回答

找到此: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;
      }
    ]);
  }
]);

其他回答

我一直在使用这种方法,它似乎工作得很好。这只是等待循环完成的时间,然后触发apply()。只需从任意位置调用函数apply(<yourscope>)。

function apply(scope) {
  if (!scope.$$phase && !scope.$root.$$phase) {
    scope.$apply();
    console.log("Scope Apply Done !!");
  } 
  else {
    console.log("Scheduling Apply after 200ms digest cycle already in progress");
    setTimeout(function() {
        apply(scope)
    }, 200);
  }
}

找到此: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;
      }
    ]);
  }
]);

如果你这样做,有时你仍然会出错(https://stackoverflow.com/a/12859093/801426).

试试看:

if(! $rootScope.$root.$$phase) {
...

保持此过程干燥的简便小助手方法:

function safeApply(scope, fn) {
    (scope.$$phase || scope.$root.$$phase) ? fn() : scope.$apply(fn);
}

我已经能够通过在我知道$digest函数将运行的地方调用$eval而不是$apply来解决这个问题。

根据文档,$apply基本上做到了这一点:

function $apply(expr) {
  try {
    return $eval(expr);
  } catch (e) {
    $exceptionHandler(e);
  } finally {
    $root.$digest();
  }
}

在我的例子中,ng单击会更改范围内的变量,而该变量上的$watch会更改必须应用$apply的其他变量。最后一步导致错误“摘要已在进行中”。

通过在watch表达式中将$apply替换为$eval,作用域变量将按预期更新。

因此,如果因为Angular中的一些其他变化,digest将以任何方式运行,那么您需要做的就是$eval‘ing。