In AngularJS, ng-repeat
is used to loop over collections and render elements dynamically. However, failing to use track by
can lead to performance issues, slow rendering, and unnecessary DOM manipulations. This article will cover:
- How
ng-repeat
works internally - Why missing
track by
causes performance degradation - Real-world examples of the problem
- How
track by
solves the issue - Best practices for optimal rendering
1. Understanding ng-repeat
and Its Performance Implications
How ng-repeat
Works Without track by
ng-repeat
loops over an array and generates a list of elements in the DOM. However, by default, AngularJS tracks objects by reference, not by a unique identifier.
Basic ng-repeat
Example Without track by
<ul>
<li ng-repeat="item in items">{{ item.name }}</li>
</ul>
When the items
array changes, AngularJS recreates the entire DOM list, even if only one item was modified. This is inefficient, especially for large datasets.
2. Why Not Using track by
Leads to Slow Rendering
When the list updates, AngularJS follows these steps:
1️⃣ Compares each element in the new array with the previous array.
2️⃣ Identifies which elements were added, removed, or modified.
3️⃣ Removes old elements and re-renders the updated elements.
Problem: AngularJS Tracks Objects by Reference
Since objects in JavaScript don’t have inherent IDs, Angular cannot differentiate elements efficiently. If you push a new item or modify an existing one, Angular destroys and recreates the entire list instead of updating specific elements.
3. Example of Performance Issue Without track by
Consider this scenario where items are dynamically updated:
<ul>
<li ng-repeat="item in items">{{ item.name }}</li>
</ul>
<button ng-click="addItem()">Add Item</button>
Controller:
$scope.items = [
{ name: "Apple" },
{ name: "Banana" },
{ name: "Cherry" }
];
$scope.addItem = function () {
$scope.items.push({ name: "Mango" });
};
Every time addItem()
is called, Angular destroys all existing DOM elements and re-renders them, even if only one item was added.
4. Solution: Using track by
for Better Performance
track by
provides a unique identifier to track each element efficiently.
Optimized Example With track by
<ul>
<li ng-repeat="item in items track by $index">{{ item.name }}</li>
</ul>
Now, AngularJS only updates the modified elements instead of re-rendering the entire list.
5. Why track by
Improves Performance
Prevents full list re-rendering – Only updates changed elements.
Reduces unnecessary DOM operations – No need to destroy/recreate elements.
Enhances UI responsiveness – Faster updates, especially in large lists.
Performance Difference:
Without track by | With track by |
---|---|
Entire list re-renders | Only changed items update |
Slower for large data | Faster rendering |
Increased CPU & memory usage | Optimized performance |
6. Using track by
with Unique IDs
If each item has a unique id
, use that instead of $index
for even better performance.
Best Practice – Track by Unique ID
<ul>
<li ng-repeat="item in items track by item.id">{{ item.name }}</li>
</ul>
Example Data:
$scope.items = [
{ id: 1, name: "Apple" },
{ id: 2, name: "Banana" },
{ id: 3, name: "Cherry" }
];
This ensures that Angular tracks items based on their actual identity instead of just their position in the array.
7. Common Mistakes and Fixes
Mistake 1: Using track by $index
for Dynamic Lists
If elements are frequently added, removed, or sorted, using $index
can still cause issues.
Problem:
<li ng-repeat="item in items track by $index">{{ item.name }}</li>
When sorting or removing items, $index
changes, leading to incorrect tracking.
Fix: Always use a unique identifier:
<li ng-repeat="item in items track by item.id">{{ item.name }}</li>
8. When to Use track by
Scenario | Use track by ? | Recommended Key |
---|---|---|
Static list (never changes) | No | N/A |
List updates frequently | Yes | Unique id |
Sorting items dynamically | Yes | Unique id |
Large datasets (500+ items) | Yes | Unique id |