如何使用 ng-repeat 循环遍历函数返回的项目? [英] How to Loop through items returned by a function with ng-repeat?
问题描述
我想重复创建div,items是一个函数返回的对象.但是以下代码报告错误:已达到 10 次 $digest() 迭代.中止!jsfiddle 在这里:http://jsfiddle.net/BraveOstrich/awnqm/
<div ng-repeat="getEntities() 中的实体">你好{{entity.id}}!
简短回答:你真的需要这样的功能还是你可以使用属性?http://jsfiddle.net/awnqm/1/
长答案
为简单起见,我将仅描述您的情况 - 对象数组的 ngRepeat.另外,我会省略一些细节.
AngularJS 使用脏检查来检测变化.当应用程序启动时,它运行 $digest
用于 $rootScope
.$digest
将对 scope 的层次结构进行深度优先遍历.所有范围都有手表列表.每个手表都有最后一个值(最初是 initWatchVal
).对于所有手表的每个范围 $digest
运行它,获取当前值 (watch.get(scope)
) 并将其与 watch.last
进行比较.如果当前值不等于 watch.last
(始终用于第一次比较)$digest
将 dirty
设置为 true
.如果 dirty == true
$digest
从 $rootScope
开始另一个深度优先遍历,则当所有范围都被处理时.$digest
在dirty == false 或遍历次数== 10 时结束.在后一种情况下,错误10 $digest() 迭代达到".将被记录.
现在关于 ngRepeat
.对于每个 watch.get
调用,它存储集合中的对象(返回 getEntities
的值),并在缓存中存储附加信息(HashQueueMap
by hashKey
).对于每个 watch.get
调用,ngRepeat
尝试从缓存中通过其 hashKey
获取对象.如果它在缓存中不存在,ngRepeat
将它存储在缓存中,创建新的作用域,在其上放置对象,创建 DOM 元素,等.
现在关于 hashKey
.通常 hashKey
是由 nextUid()
.但它可以是函数.hashKey
生成后保存在对象中,以备将来使用.
为什么你的例子会产生错误:函数 getEntities()
总是返回带有新对象的数组.这个对象没有 hashKey
并且不存在于 ngRepeat
缓存中.因此,每个 watch.get
上的 ngRepeat
都会为它生成新的作用域,并为 {{entity.id}}
生成新的 watch.这个手表在第一个 watch.get
有 watch.last == initWatchVal
.所以 watch.get() != watch.last
.所以 $digest
开始新的遍历.所以 ngRepeat
用新的手表创建新的作用域.所以......在 10 次遍历后你会得到错误.
如何解决
- 不要在每次
getEntities()
调用时创建新对象. - 如果您需要创建新对象,您可以为它们添加
hashKey
方法.有关示例,请参阅本主题.
希望了解 AngularJS 内部原理的人会在我做错了什么时纠正我.
I want to create divs repeatedly, the items is objects returned by a function. However the following code report errors: 10 $digest() iterations reached. Aborting! jsfiddle is here: http://jsfiddle.net/BraveOstrich/awnqm/
<body ng-app>
<div ng-repeat="entity in getEntities()">
Hello {{entity.id}}!
</div>
</body>
Short answer: do you really need such function or you can use property? http://jsfiddle.net/awnqm/1/
Long answer
For simplicity I will describe only your case - ngRepeat for array of objects. Also, I'll omit some details.
AngularJS uses dirty checking for detecting changes. When application is started it runs $digest
for $rootScope
. $digest
will do depth-first traversal for scope's hierarchy. All scopes have list of watches. Each watch has last value (initially initWatchVal
). For each scope for all watches $digest
runs it, gets current value (watch.get(scope)
) and compares it to watch.last
. If current value is not equal to watch.last
(always for first compare) $digest
sets dirty
to true
. When all scopes are processed if dirty == true
$digest
starts another depth-first traversal from $rootScope
. $digest
ends when dirty == false or number of traversals == 10. In the latter case, the error "10 $digest() iterations reached." will be logged.
Now about ngRepeat
. For each watch.get
call it stores objects from collection (returning value of getEntities
) with additional information in cache (HashQueueMap
by hashKey
). For every watch.get
call ngRepeat
tries to get object by its hashKey
from cache. If it does not exist in cache, ngRepeat
stores it in cache, creates new scope, puts object on it, creates DOM element, etc.
Now about hashKey
. Usually hashKey
is unique number generated by nextUid()
. But it can be function. hashKey
is stored in object after generating for future use.
Why your example generates error: function getEntities()
always returns array with new object. This object doesn't have hashKey
and doesn't exist in ngRepeat
cache. So ngRepeat
on each watch.get
generates new scope for it with new watch for {{entity.id}}
. This watch on first watch.get
has watch.last == initWatchVal
. So watch.get() != watch.last
. So $digest
starts new traverse. So ngRepeat
creates new scope with new watch. So ... after 10 traverses you get error.
How you can fix it
- Do not create new objects on every
getEntities()
call. - If you need to create new objects you can add
hashKey
method for them. See this topic for examples.
Hope people who know AngularJS internals will correct me if I'm wrong in something.
这篇关于如何使用 ng-repeat 循环遍历函数返回的项目?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!