如何使用ng-repeat循环执行函数返回的项目?

Xia*_*com 112 angularjs

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

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

Art*_*eev 193

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

答案很长

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

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

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

现在约hashKey.通常hashKey是由生成的唯一编号nextUid().但它可以是功能.hashKey生成后存储在对象中以备将来使用.

为什么您的示例生成错误:function getEntities()始终返回带有新对象的数组.此对象hashKeyngRepeat缓存中不存在和不存在.因此ngRepeat,每个都watch.get为新手表创造了新的范围{{entity.id}}.这款手表首先watch.getwatch.last == initWatchVal.所以watch.get() != watch.last.所以$digest开始新的遍历.因此,ngRepeat使用新手表创造新范围.所以......经过10次遍历后,你会收到错误.

你如何解决它

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

希望知道AngularJS内部人员的人会纠正我,如果我错了什么的话.

  • 很棒的答案,很棒的细节,谢谢."希望知道AngularJS内部人员的人"......呃,认为那是你,兄弟. (36认同)
  • +1谢谢你.我有同样的问题,不能使用静态属性.应该在手册IMO的ngRepeat页面上记录$$ hashKey. (4认同)
  • 所以遵循"不要在每个getEntities()调用上创建新对象"的建议.可以很容易地修复它:`<div ng-repeat ="entity in entity =(entities || getEntities())"> ` (2认同)
  • 我之前评论的解决方案适用于`getEntities()`总是返回相同的数组,如果数组发生变化,你将不会在`ng-repeat`中得到它 (2认同)

小智 43

在重复之外初始化数组

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

  • 如果`getEntities()`在程序的生命周期中返回不同的东西,这不起作用.例如,假设`getEntities()`触发`$ http.get`.当get get resolve(你进行了AJAX调用)时,`entities`已经被初始化了. (8认同)
  • 来自angular文档`ngInit的唯一合适用途是用于别名ngRepeat的特殊属性.除了这种情况,您应该使用控制器而不是ngInit来初始化范围上的值 (3认同)

Den*_*nis 15

这是在这里报道并得到这样的回应:

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

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

如果将阵列移动到主控制器外,您可以看到此行为消失:

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

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

我们通过将控制器方法的结果分配给属性来解决这个问题,然后执行ng:重复它.


Aga*_*gat 7

基于@przno评论

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

BTW第二个解决方案@Artem Andreev建议不使用Angular 1.1.4及更高版本,而第一个解决方案并不能解决问题.所以,我担心现在这是一个没有尖端的解决方案,没有功能上的缺点