Using track by
in ng-repeat
is an important optimization technique in AngularJS to improve the performance of rendering lists, particularly when dealing with large datasets. By default, AngularJS uses object identity to determine whether a DOM element needs to be re-rendered when the data in an ng-repeat
changes. This can lead to unnecessary re-rendering, especially if the data changes frequently or contains large lists of items.
Why use track by
?
By default, AngularJS re-renders the entire list of elements whenever the data in the list changes. This is because AngularJS tracks the DOM elements by their identity. When the list is updated, AngularJS compares the current list of elements with the previous one to determine which elements should be added, removed, or updated.
However, this approach can be inefficient if you have a large list and only a small part of the list changes. It may lead to unnecessary DOM manipulations, which could significantly degrade performance.
Using track by
allows you to instruct AngularJS to track items in the list by a unique identifier (usually an ID) rather than by their reference or index. This way, AngularJS can efficiently update only the items that have changed, rather than re-rendering the entire list.
How to use track by
The track by
keyword is followed by an expression that returns a unique identifier for each item in the list. This identifier helps AngularJS to track and update the correct DOM elements. Here’s an example of how to use track by
in ng-repeat
:
Basic Example:
Let’s assume you have a list of items where each item has an id
and a name
. You want to render this list using ng-repeat
, and you want AngularJS to track each item by its unique id
to avoid unnecessary DOM updates.
<div ng-app="myApp" ng-controller="myController">
<ul>
<li ng-repeat="item in items track by item.id">
{{ item.name }}
</li>
</ul>
</div>
JavaScript:
angular.module('myApp', [])
.controller('myController', function($scope) {
$scope.items = [
{ id: 1, name: 'Item 1' },
{ id: 2, name: 'Item 2' },
{ id: 3, name: 'Item 3' }
];
// Function to modify the list
$scope.modifyList = function() {
// Modify the list, for example, add or remove an item
$scope.items.push({ id: 4, name: 'Item 4' });
};
});
Explanation:
- In the example above,
ng-repeat="item in items track by item.id"
is used. Here,track by item.id
tells AngularJS to track each item in theitems
array by its uniqueid
instead of the default behavior, which is tracking by object identity. - This means that if you add, remove, or modify an item, AngularJS will only re-render the affected item in the DOM, rather than the entire list. This results in better performance, especially with large datasets.
When to use track by
:
- Large datasets: When you’re working with large datasets (for example, 1000+ items),
track by
can significantly improve performance by minimizing DOM manipulations. - Dynamic lists: If your list is frequently updated (e.g., adding, removing, or modifying items), using
track by
ensures that AngularJS can efficiently update only the changed elements rather than re-rendering the entire list. - Complex data: If the objects in your list are complex and have many properties, tracking them by a unique identifier (
id
, for example) avoids unnecessary DOM re-renders when only the data of one object changes.
Avoiding Common Pitfalls
- Tracking by the wrong property: Ensure that the property you’re using with
track by
is always unique for each item. If the property is not unique (e.g., usingindex
or a non-unique value), AngularJS may still re-render unnecessary elements. For example, avoid using: htmlCopyEdit<li ng-repeat="item in items track by $index">
This can cause inefficiency, especially when items are reordered or updated. track by
with dynamic collections: If the collection is dynamic and items are frequently added or removed, using a unique identifier helps AngularJS avoid mistakenly destroying and recreating DOM elements unnecessarily.
Performance Comparison
Without track by
, AngularJS will compare the entire list of elements, and if the list is large, this can cause performance issues.
<li ng-repeat="item in items">{{ item.name }}</li>
With track by
:
<li ng-repeat="item in items track by item.id">{{ item.name }}</li>
In the case of frequent updates, using track by
ensures that only the modified items are updated in the DOM, leading to fewer changes in the DOM and better overall performance.
Example with Dynamic Updates:
Let’s demonstrate the performance improvement with dynamic updates:
<div ng-app="myApp" ng-controller="myController">
<button ng-click="modifyList()">Modify List</button>
<ul>
<li ng-repeat="item in items track by item.id">
{{ item.name }}
</li>
</ul>
</div>
JavaScript:
angular.module('myApp', [])
.controller('myController', function($scope) {
$scope.items = [
{ id: 1, name: 'Item 1' },
{ id: 2, name: 'Item 2' },
{ id: 3, name: 'Item 3' }
];
// Function to modify the list
$scope.modifyList = function() {
// Modify the list, for example, add or remove an item
$scope.items.push({ id: 4, name: 'Item 4' });
};
});
Here, when you click the “Modify List” button, AngularJS will efficiently add a new item without unnecessarily re-rendering the entire list. This is because we’re using track by item.id
, so only the new item gets added.