115

我想重复创建 div,项目是函数返回的对象。但是下面的代码报告错误: 10 $digest() 达到了迭代。中止!jsfiddle 在这里:http: //jsfiddle.net/BraveOstrich/awnqm/

<body ng-app>
  <div ng-repeat="entity in getEntities()">
    Hello {{entity.id}}!
  </div>
</body>
4

4 回答 4

198

简短回答:您真的需要这样的功能还是可以使用属性?http://jsfiddle.net/awnqm/1/

长答案

为简单起见,我将仅描述您的情况 - ngRepeat 用于对象数组。另外,我会省略一些细节。

AngularJS 使用脏检查来检测变化。当应用程序启动时,它运行$digest. 将对范围的层次结构进行深度优先遍历。所有范围都有手表列表。每个手表都有最后一个值(最初)。对于所有手表的每个范围都运行它,获取当前值 ( ) 并将其与. 如果当前值不等于(始终用于第一次比较)设置为. 如果从 开始另一个深度优先遍历,则处理所有范围时。当脏 == false 或遍历次数 == 10 时结束。在后一种情况下,错误“达到 10 $digest() 迭代”。将被记录。$rootScope$digestinitWatchVal$digestwatch.get(scope)watch.lastwatch.last$digestdirtytruedirty == true $digest$rootScope$digest

现在关于ngRepeat. 对于每个watch.get调用,它都会将集合中的对象(的返回值getEntities)与缓存中的附加信息(HashQueueMapby hashKey)一起存储。对于每个watch.get调用ngRepeat都尝试通过其hashKey从缓存中获取对象。如果缓存中不存在,则将其ngRepeat存储在缓存中,创建新范围,将对象放在其上,创建 DOM 元素

现在关于hashKey. 通常hashKey是由 生成的唯一编号nextUid()。但它可以是函数hashKey生成后存储在对象中以供将来使用。

为什么您的示例会产生错误:函数getEntities()总是返回带有新对象的数组。该对象没有hashKey也不存在于ngRepeat缓存中。因此ngRepeat,在每个watch.get使用新的 watch 为它生成新的范围时{{entity.id}}。这只表首先watch.getwatch.last == initWatchVal。所以watch.get() != watch.last。于是$digest开始了新的穿越。所以ngRepeat用新手表创造了新的范围。所以......经过 10 次遍历后,您会收到错误消息。

你怎么能解决它

  1. 不要在每次getEntities()调用时创建新对象。
  2. 如果您需要创建新对象,您可以hashKey为它们添加方法。有关示例,请参阅本主题

希望了解 AngularJS 内部原理的人如果我在某些方面错了,会纠正我。

于 2012-09-09T16:26:19.417 回答
44

在重复之外初始化数组

<body ng-app>
   <div ng-init="entities = getEntities()">
       <div ng-repeat="entity in entities">
           Hello {{entity.id}}!
       </div>
   </div>
</body>
于 2014-04-09T15:47:06.313 回答
15

这是在此处报告并得到以下回复:

您的 getter 不是幂等的并且会更改模型(通过每次调用它时生成一个新数组)。这迫使 angular 继续调用它,希望模型最终能稳定下来,但它从来没有这样做,所以 angular 放弃并抛出异常。

getter 返回的值相等但不相同,这就是问题所在。

如果将数组移到主控制器之外,您可以看到此行为消失:

var array = [{id:'angularjs'}];
function Main($scope) {
    $scope.getEntities = function(){return array;};
};

因为现在它每次都返回相同的对象。您可能需要重新构建模型以使用范围上的属性而不是函数:

我们通过将控制器方法的结果分配给一个属性来解决它,并对它执行 ng:repeat。

于 2012-09-09T13:54:32.273 回答
8

基于@przno 评论

<body ng-app>
  <div ng-repeat="item in t = angular.equals(t, getEntities()) ? t : getEntities()">
    Hello {{item.id}}!
  </div>
</body>

顺便说一句,@Artem Andreev 建议第二个解决方案在 Angular 1.1.4 及更高版本中不起作用,而第一个解决方案不能解决问题。所以,我担心现在这是一个不那么尖锐的解决方案,没有功能上的缺点

于 2015-01-06T21:10:31.397 回答