如何循环ng-repeat函数返回的项目?

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

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

简短的回答 :你真的需要这样的function,或者你可以使用财产? http://jsfiddle.net/awnqm/1/

长答案

为了简单起见,我只描述你的情况 – 对象数组的ngRepet。 另外,我会省略一些细节。

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

现在关于ngRepeat 。 对于每个watch.get调用它存储集合中的对象(返回getEntities值)与caching中的HashQueueMap信息(通过hashKey )。 对于每个watch.get调用ngRepeat尝试通过其caching中的hashKey获取对象。 如果在caching中不存在, ngRepeat将其存储在caching中,创build新的作用域,将对象放在caching中,创buildDOM元素等 。

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

为什么你的例子产生错误 :函数getEntities()总是返回数组与新的对象。 这个对象没有hashKey ,在ngRepeatcaching中不存在。 因此,每个ngRepeat上的watch.get{{entity.id}}新手表生成新的范围。 第一个watch.get上的这个表具有watch.last == initWatchVal 。 所以watch.get() != watch.last 。 所以$digest开始新的遍历。 所以ngRepeat用新手表创build新的范围。 所以…经过10遍后,你会得到错误。

你如何解决它

  1. 不要在每个getEntities()调用中创build新的对象。
  2. 如果你需要创build新的对象,你可以为它们添加hashKey方法。 看到这个主题的例子。

希望那些认识AngularJS内部的人纠正我,如果我错了什么。

初始化重复之外的数组

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

这是在这里报告 ,得到了这样的回应:

你的getter不是幂等的并且改变模型(每次调用时都会生成一个新的数组)。 这迫使angular度继续调用它,希望模型最终稳定,但它永远不会放弃,并抛出一个例外。

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

如果将arrays移到主控制器外面,您可以看到这种行为消失:

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

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

我们通过将控制器方法的结果分配给一个属性来解决这个问题,并且对其进行重复。

根据@przno评论

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

BTW的第二个解决scheme@Artem Andreevbuild议在1.1.4以上版本的Angular中不工作,而第一个解决不了这个问题。 所以,现在我恐怕这是没有缺点的解决scheme