How to Loop through items returned by a function with ng-repeat?

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

  1. Do not create new objects on every getEntities() call.
  2. 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.

Leave a Comment