我想重复创建 div,项目是函数返回的对象。但是下面的代码报告错误: 10 $digest() 达到了迭代。中止!jsfiddle 在这里:http: //jsfiddle.net/BraveOstrich/awnqm/
<body ng-app>
<div ng-repeat="entity in getEntities()">
Hello {{entity.id}}!
</div>
</body>
我想重复创建 div,项目是函数返回的对象。但是下面的代码报告错误: 10 $digest() 达到了迭代。中止!jsfiddle 在这里:http: //jsfiddle.net/BraveOstrich/awnqm/
<body ng-app>
<div ng-repeat="entity in getEntities()">
Hello {{entity.id}}!
</div>
</body>
简短回答:您真的需要这样的功能还是可以使用属性?http://jsfiddle.net/awnqm/1/
长答案
为简单起见,我将仅描述您的情况 - ngRepeat 用于对象数组。另外,我会省略一些细节。
AngularJS 使用脏检查来检测变化。当应用程序启动时,它运行$digest
. 将对范围的层次结构进行深度优先遍历。所有范围都有手表列表。每个手表都有最后一个值(最初)。对于所有手表的每个范围都运行它,获取当前值 ( ) 并将其与. 如果当前值不等于(始终用于第一次比较)设置为. 如果从 开始另一个深度优先遍历,则处理所有范围时。当脏 == false 或遍历次数 == 10 时结束。在后一种情况下,错误“达到 10 $digest() 迭代”。将被记录。$rootScope
$digest
initWatchVal
$digest
watch.get(scope)
watch.last
watch.last
$digest
dirty
true
dirty == true
$digest
$rootScope
$digest
现在关于ngRepeat
. 对于每个watch.get
调用,它都会将集合中的对象(的返回值getEntities
)与缓存中的附加信息(HashQueueMap
by hashKey
)一起存储。对于每个watch.get
调用ngRepeat
都尝试通过其hashKey
从缓存中获取对象。如果缓存中不存在,则将其ngRepeat
存储在缓存中,创建新范围,将对象放在其上,创建 DOM 元素等。
现在关于hashKey
. 通常hashKey
是由 生成的唯一编号nextUid()
。但它可以是函数。hashKey
生成后存储在对象中以供将来使用。
为什么您的示例会产生错误:函数getEntities()
总是返回带有新对象的数组。该对象没有hashKey
也不存在于ngRepeat
缓存中。因此ngRepeat
,在每个watch.get
使用新的 watch 为它生成新的范围时{{entity.id}}
。这只表首先watch.get
有watch.last == initWatchVal
。所以watch.get() != watch.last
。于是$digest
开始了新的穿越。所以ngRepeat
用新手表创造了新的范围。所以......经过 10 次遍历后,您会收到错误消息。
你怎么能解决它
getEntities()
调用时创建新对象。hashKey
为它们添加方法。有关示例,请参阅本主题。希望了解 AngularJS 内部原理的人如果我在某些方面错了,会纠正我。
在重复之外初始化数组
<body ng-app>
<div ng-init="entities = getEntities()">
<div ng-repeat="entity in entities">
Hello {{entity.id}}!
</div>
</div>
</body>
这是在此处报告并得到以下回复:
您的 getter 不是幂等的并且会更改模型(通过每次调用它时生成一个新数组)。这迫使 angular 继续调用它,希望模型最终能稳定下来,但它从来没有这样做,所以 angular 放弃并抛出异常。
getter 返回的值相等但不相同,这就是问题所在。
如果将数组移到主控制器之外,您可以看到此行为消失:
var array = [{id:'angularjs'}];
function Main($scope) {
$scope.getEntities = function(){return array;};
};
因为现在它每次都返回相同的对象。您可能需要重新构建模型以使用范围上的属性而不是函数:
我们通过将控制器方法的结果分配给一个属性来解决它,并对它执行 ng:repeat。
基于@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 及更高版本中不起作用,而第一个解决方案不能解决问题。所以,我担心现在这是一个不那么尖锐的解决方案,没有功能上的缺点