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-repeatworks internally - Why missing
track bycauses performance degradation - Real-world examples of the problem
- How
track bysolves 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 |
