错误:达到10次$ digest()迭代。流产!具有动态sortby谓词


134

我有以下代码重复并显示用户名及其分数:

<div ng-controller="AngularCtrl" ng-app>
  <div ng-repeat="user in users | orderBy:predicate:reverse | limitTo:10">
    <div ng-init="user.score=user.id+1">
        {{user.name}} and {{user.score}}
    </div>
  </div>
</div>

以及相应的角度控制器。

function AngularCtrl($scope) {
    $scope.predicate = 'score';
    $scope.reverse = true;
    $scope.users = [{id: 1, name: 'John'}, {id: 2, name: 'Ken'}, {id: 3, name: 'smith'}, {id: 4, name: 'kevin'}, {id: 5, name: 'bob'}, {id: 6, name: 'Dev'}, {id: 7, name: 'Joe'}, {id: 8, name: 'kevin'}, {id: 9, name: 'John'}, {id: 10, name: 'Ken'}, {id: 11, name: 'John'}, {id: 1, name: 'John'}, {id: 2, name: 'Ken'}, {id: 3, name: 'smith'}, {id: 4, name: 'kevin'}, {id: 5, name: 'bob'}, {id: 6, name: 'Dev'}, {id: 7, name: 'Joe'}, {id: 8, name: 'kevin'}, {id: 9, name: 'John'}, {id: 10, name: 'Ken'}]
}

当我运行上面的代码时,出现错误:达到10个$ digest()迭代。流产!我的控制台错误。

我已经为它创建了jsfiddle

排序谓词仅在ng-repeat内部初始化,并且限制也应用于对象数。所以我觉得将sortby和limitTo监视者放在一起是错误的原因。

如果$ scope.reverse为false(分数的升序),则它不会出错。

谁能帮我了解这是怎么回事?非常感谢您的帮助。


如果删除if语句,它仍然会出错吗?
Mathew Berg

感谢您的回应Mathew!我错误地诊断了这个问题。问题似乎与sortby和limitTo过滤器有关。我已经用JSFiddle更新了问题。非常感谢您的帮助。
胖男孩

这是一个有角度的事情。您需要记住自己的功能,然后记住状态。在stackoverflow.com/questions/14376879/…
Julio Marins

Answers:


116

请检查此jsFiddle。(代码基本上与您发布的代码相同,但是我使用元素而不是窗口来绑定滚动事件)。

据我所知,您发布的代码没有问题。创建属性更改循环时,通常会发生您提到的错误。例如,当您监视某个属性的更改,然后在侦听器上更改该属性的值时,就像这样:

$scope.$watch('users', function(value) {
  $scope.users = [];
});

这将导致错误消息:

未捕获的错误:达到10个$ digest()迭代。流产!
观察者在最近5次迭代中解雇了:...

确保您的代码没有这种情况。

更新:

这是你的问题:

<div ng-init="user.score=user.id+1"> 

您不应该在渲染过程中更改对象/模型,否则,它将强制执行新的渲染(因此将导致循环,从而导致“错误:达到10次$ digest()迭代。异常终止!”)。

如果要更新模型,请在Controller或Directive上执行,而不要在视图上执行。angularjs文件建议不使用ng-init完全相同,以避免这些种情况:

在模板中使用ngInit指令(仅适用于玩具/示例应用,不建议用于实际应用)

这是一个带有工作示例的jsFiddle


1
仅供参考,angular.element(w).bind()您可以使用代替element.bind()
Mark Rajcok

非常感谢bmleite和Mark。我错误地诊断了这个问题。请在上方查看我的评论。我已经用JSFiddle更新了问题。非常感谢您的帮助。
胖男孩

非常感谢@bmleite!只是想了解更多。但是,为什么$ scope.reverse = false(分数的升序)不会导致错误呢?
胖男孩

对于上升和下降,应该分别使用前缀“ +”和“-”(即“ + score”和“ -score”)。更多信息请参见这里
bmleite

1
这个答案解决了我的问题。这种解释很好地描述了问题:尝试在循环浏览时同时修改属性时,将导致$ digest()迭代错误。因此,每次属性更改都会触发视图(UI)的更新,并且角度最终会在10个循环时达到最大值。jsFiddle示例将属性更改放入Controller。在视图中更改属性会导致此错误。
mbokil 2013年

9

对我来说,这个错误的原因是...

ng-if="{{myTrustSrc(chat.src)}}"

在我的模板中

它导致控制器中的函数myTrustSrc在无限循环中被调用。如果我从这一行中删除ng-if,那么问题就解决了。

<iframe ng-if="chat.src" id='chat' name='chat' class='chat' ng-src="{{myTrustSrc(chat.src)}}"></iframe>

不使用ng-if时,该函数仅被调用几次。我仍然想知道为什么用ng-src多次调用该函数?

这是控制器中的功能

$scope.myTrustSrc = function(src) {
    return $sce.trustAsResourceUrl(src);
}

我仍然想知道为什么用ng-src多次调用该函数?-因为angular尝试创建html几次,直到它得到2个相同的结果。这就是错误10 $ digest()迭代达到的含义,他尝试了10次,但从未得到2个相同的结果
bresleveloper 2015年

@bresleveloper您可以提供此信息的链接吗?谢谢。
威拉2015年

@Willa在这里docs.angularjs.org/api/ng/type/$rootScope.Scope CTRF + F这个“重新运行的迭代限制是10,以防止无限循环死锁”
bresleveloper

谢谢。有帮助。
威拉2015年

7

对我来说,我是将函数结果作为2路绑定输入“ =”传递给每次创建新对象的指令。

所以我有这样的事情:

<my-dir>
   <div ng-repeat="entity in entities">
      <some-other-dir entity="myDirCtrl.convertToSomeOtherObject(entity)"></some-other-dir>
   </div>
</my-dir>

而my-dir上的控制器方法是

this.convertToSomeOtherObject(entity) {
   var obj = new Object();
   obj.id = entity.Id;
   obj.value = entity.Value;
   [..]
   return obj;
}

当我做了

this.convertToSomeOtherObject(entity) {
   var converted = entity;
   converted.id = entity.Id;
   converted.value = entity.Value;
   [...]
   return converted;
}

解决了问题!

希望这会帮助某人:)


5

我有另一个导致这种情况的例子。希望它对将来的参考有所帮助。我正在使用AngularJS 1.4.1。

我有多次调用自定义指令的标记:

<div ng-controller="SomeController">
    <myDirective data="myData.Where('IsOpen',true)"></myDirective>
    <myDirective data="myData.Where('IsOpen',false)"></myDirective>
</div>

myData是一个数组,并且Where()是一个扩展方法,它在该数组上进行迭代,返回一个新数组,该数组包含IsOpen属性与第二个参数中的bool值匹配的原始项。

在控制器中,我这样设置$scope.data

DataService.getData().then(function(results){
    $scope.data = results;
});

问题是Where()从指令中调用扩展方法,就像上面的标记一样。要解决此问题,我将对扩展方法的调用移到了控制器中,而不是在标记中:

<div ng-controller="SomeController">
    <myDirective data="openData"></myDirective>
    <myDirective data="closedData"></myDirective>
</div>

和新的控制器代码:

DataService.getData().then(function(results){
    $scope.openData = results.Where('IsOpen',true);
    $scope.closedData = results.Where('IsOpen',false);
});

听起来完全像我的问题。一个简单的函数,不更新任何内容,而是创建一个本地数组,在一个现有的$ scope数组上进行迭代,并在该本地数组中创建对象,然后返回。通过调用一次并将其存储在$ scope成员中,可以解决此问题。谢谢。希望我知道直接使用该方法的问题是什么。
AgilePro 2015年

2

参加聚会的时间很晚,但是我的问题正在发生,因为角度1.5.8中的ui路由器存在缺陷。值得一提的是,该错误仅在我第一次运行该应用程序时出现,此后不会再次发生。 来自github的帖子解决了我的问题。基本上,错误涉及$urlRouterProvider.otherwise("/home") 。解决方案是这样的解决方法:

$urlRouterProvider.otherwise(function($injector, $location) {
   var $state = $injector.get("$state");
   $state.go("your-state-for-home");
});

2

对于初学者,忽略所有答案,并告诉您使用$ watch。Angular已经脱离了侦听器。我向您保证,您只是在朝着这个方向思考,就会使事情变得复杂。

忽略所有告诉您$ timeout用户的答案。您不知道页面加载需要多长时间,因此这不是最佳解决方案。

您只需要知道页面何时渲染即可。

<div ng-app='myApp'>
<div ng-controller="testctrl">
    <label>{{total}}</label>
    <table>
      <tr ng-repeat="item in items track by $index;" ng-init="end($index);">
        <td>{{item.number}}</td>
      </tr>
    </table>
</div>

var app = angular.module('myApp', ["testctrl"]);
var controllers = angular.module("testctrl", []);
 controllers.controller("testctrl", function($scope) {

  $scope.items = [{"number":"one"},{"number":"two"},{"number":"three"}];

  $scope.end = function(index){
  if(index == $scope.items.length -1
        && typeof $scope.endThis == 'undefined'){

            ///  DO STUFF HERE
      $scope.total = index + 1;
      $scop.endThis  = true;
 }
}
});

通过$ index跟踪ng-repeat,当数组的长度等于索引时停止循环并执行逻辑。

jsfiddle


1

我在角度树控件的上下文中遇到此错误。就我而言,这是树的选择。我从一个函数返回treeOptions()。它总是返回相同的对象。但是Angular神奇地认为它是一个新对象,然后导致摘要循环开始。导致摘要的递归。解决方案是将treeOptions绑定到范围。并只分配一次。


1

太奇怪了...我有完全相同的错误,来自另一件事。创建控制器时,我传递了$ location参数,如下所示:

App.controller('MessageController', function ($scope, $http, $log, $location, $attrs, MessageFactory, SocialMessageFactory) {
   // controller code
});

事实证明这是一个错误 当我们使用第三方库或纯JS操作某些细节(此处为window.location)时,,下一角度的摘要将消除此错误。

因此,我只是从控制器创建参数中删除了$ location,然后它再次工作,没有出现此错误。或者,如果您绝对需要使用angular的$ location,则必须删除<a href="#">link</a>模板页面链接中的每一个,而要写href =“”。为我工作。

希望有一天能对您有所帮助。



0

将Firefox升级到版本51之后clearing the cache,这种情况就发生在我身上。之后,问题就消失了。


0

我有类似的错误,因为我已经定义

ng-class =“ GetLink()”

代替

ng-click =“ GetLink()”


0

当使用$ sce.trustAsResourceUrl()作为从ng-src调用的函数的返回值时,从角度1.6-> 1.7升级后,这发生在我身上。您可以看到此处提到的这个问题

就我而言,我必须更改以下内容。

<source ng-src="{{trustSrc(someUrl)}}" type='video/mp4' />
trustSrc = function(url){
    return $sce.trustAsResourceUrl(url);
};

<source ng-src='{{trustedUrl}} type='video/mp4' />
trustedUrl = $sce.trustAsResourceUrl(someUrl);

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.