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

时间:2012-09-09 06:01:33

标签: angularjs

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

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

4 个答案:

答案 0 :(得分:189)

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

答案很长

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

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

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

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

为什么您的示例会生成错误:function getEntities()始终返回带有新对象的数组。此对象没有hashKey,并且在ngRepeat缓存中不存在。因此,每个ngRepeat上的watch.get会为{{entity.id}}的新监视为其创建新范围。第一个watch.get上的此手表有watch.last == initWatchVal。所以watch.get() != watch.last。所以$digest开始新的遍历。所以ngRepeat使用新手表创建新范围。所以...经过10次遍历后,你会收到错误。

如何修复

  1. 不要在每次getEntities()来电时创建新对象。
  2. 如果您需要创建新对象,可以为它们添加hashKey方法。有关示例,请参阅this topic
  3. 希望知道AngularJS内部人员的人在我出错的时候会纠正我。

答案 1 :(得分:42)

在重复

之外初始化数组
<body ng-app>
   <div ng-init="entities = getEntities()">
       <div ng-repeat="entity in entities">
           Hello {{entity.id}}!
       </div>
   </div>
</body>

答案 2 :(得分:15)

这是reported here并得到了回应:

  
    

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

         

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

  

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

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

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

  
    

我们通过将控制器方法的结果分配给属性来解决它,然后对它进行重复:重复它。

  

答案 3 :(得分:7)

基于@przno评论

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

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