3

I'm trying to make ng-repeat over function call result, like

<body ng-init='a = [1, 2, 3]'>
  <div ng-repeat='item in f(a) track by item[0]'>{{item}}</div>
</body>

where f is

function f (arr) {
    return arr.map(function (v) {
      return [v]
    })
  }

Here is Plunker with this code

Problem is that in console we can see errors like 10 $digest() iterations reached. Aborting!

This is not because of recreating container array, because if we just modify line 3 like

return [v] -> return v

and remove

track by item[0] 

everything works. This is because of recreating items, and track by should handle this. But for some reason it doesn't :(

I was also trying to solve the problem without track by buy putting constant $$hashKey on each item (even on collection itself). Here is Plunker with same error. Hope some one could explain why this is not working

So there is two separate questions: case with track by and case with $$hashKey

BTW Yes, I read How to Loop through items returned by a function with ng-repeat? and AngularJS InfDig error (infinite loop) with ng-repeat function that returns array of objects more than a few times, but can't find an answer there

Thanks

Community
  • 1
  • 1
Agat
  • 358
  • 2
  • 10
  • I've done some investigation and found https://groups.google.com/forum/#!topic/angular/IEIQok-YkpU where people discus my real problem, simplified which I get current question. Solutions they have, as well as my second (with `$$hashKey` manipulation) are working in old angular and does not work in modern version. I think brake had come in 1.1.3 -> 1.1.4, just when `track by` came in to Angular – Agat Jan 06 '15 at 16:33

2 Answers2

1

Is there any reason you can't compute the result and then display it? I.e. have ng-init="a = [0,1,2]; fa = f(a);" and then ng-repeat="item in fa" ?

Working plunkr example

If you need to have that computed result updated when a changes you could just have a $scope.$watch statement watching for changes to a and then updating fa.

KhalilRavanna
  • 5,768
  • 3
  • 28
  • 24
  • There is a lot of ways I can work around this. But, at first, they are less straight forward according to things I'm trying to implement, and in second I want to understand what is wrong with my current vision of how it should work – Agat Jan 05 '15 at 14:43
  • Ok I think I understand. That being said, my 2 cents would be that `ng-repeat` can often be a source of heavy inefficiency in angular, and it's best to leave as little logic in an `ng-repeat` directive as possible. That's why I'd suggest precomputing your values before you pass them off to the directive. Not only that, manually updating your values instead of letting angular "decide" when to update them for you can also make things more efficient, and honestly, more clear as to what's happening. – KhalilRavanna Jan 05 '15 at 15:08
  • This is not about logic, it is about data binding: solving this problem with `$watch` we prevent Angular from doing what he created to - bind data without support code (at list `track by` case) – Agat Jan 05 '15 at 15:27
  • I'm confused by the need for `track by`. `track by` is just for explicitly determining the identity of elements in an array so as to tell them apart from one another and map them to dom elements. What seems to be happening, regardless of `track by` is that angular, for whatever reason, when iterating through a function that returns arrays of arrays, causes a recursive update loop. In this [forked plunkr](http://plnkr.co/edit/iMaVMPFLz5ojnzRWpC0G?p=preview), I messed with the data and you can see what angular seems to think is being changed/updated. – KhalilRavanna Jan 05 '15 at 16:28
  • There might be a way to stop angular from being "stupid" here, and I'm sure someone smarter than I or with more time on their hands to dig through the source code could figure it out and explain it. In the end though, it seems like it might be easier to sidestep the whole thing and not leave the updating to angular. – KhalilRavanna Jan 05 '15 at 16:33
  • Yup, in your example we could see in console that each time there are new elements in array, with new `$$hashKey`s, and that is the reason why he updating in loop. And there is no `$$hashKey`s in `track by` case, and equal `$$hashKey`s in explicit `$$hashKey` setting case... that is unclear part - why does he continue to check/update. In any case - thank you for your time, I appreciate your help – Agat Jan 05 '15 at 16:59
0

Ok, here is hack we could use to solve the case without track by or $$hashKey

ng-repeat="item in t = angular.equals(t, f(a)) ? t : f(a)"

But this does answer the question why examples in question are does not work. So, please, if you know the answer - post it - I would be very grateful

Agat
  • 358
  • 2
  • 10