Last Updated: February 25, 2016
·
2.637K
· lucasroesler

Angular track by optimization and arrays

If you do a search on the web for Angular ng-repeat, you will of course get the documentation for ng-repeat, but you will also find several blog posts about how to optimize ng-repeat by using the track by option. See http://www.codelord.net/2014/04/15/improving-ng-repeat-performance-with-track-by/, for example. Aviv uses the following example

<ul class="tasks">
    <li ng-repeat="task in tasks" ng-class="{done: task.done}">
        {{task.id}}: {{task.title}}
    </li>
</ul>

Here the code assumes an array of task objects, e.g.

$scope.tasks = [{id: 1, title: "First task"}, ...]

With this code, when tasks is updated, say a new task is pushed on the end of the array, Angular will deconstruct and completely build the li elements in the ng-repeat. It would be awesome if angular only updated the modified tasks and the related DOM elements. We can do this with the simple change of

ng-repeat="task in tasks track by $index"

of

ng-repeat="task in tasks track by task.id"

However, track by can seems like a bug if you are repeating a list like the following [0,0,1,2,3] and it updated to [0,1,2,3,4]. In this case, the tracking value, $index, never changes, so the DOM elements will not be updated. Here is my fix:

ng-repeat="value in arrasy track by array_hash($index, value)"

where

$scope.array_hash = function(index, value) {
    return String($index) + '-' + String(value);
}

Now, the track by value changes for both index and value changes. Of course there are problems here, I am assuming that String(value) makes sense. You will have to modify as appropriate for your use case.