Angular

Understanding the track Function in Angular 17-18: The Role of Track by in the @for Loop

Angular last versions

Angular 17-18 introduces a more intuitive and powerful syntax for handling iteration over collections in templates. One of the key features within this new syntax is the track function, which is used to optimize how Angular handles updates in lists during iteration. In this article, we’ll explore what the track function does in Angular’s @for loop, why it’s important, and how it improves performance in web applications.

The Problem: Inefficient DOM Updates in Loops

Before diving into the track function, it’s important to understand the issue it solves.

In Angular applications, when you iterate over a list using the traditional *ngFor directive, Angular keeps track of changes in that list and updates the DOM accordingly. Without proper tracking, Angular will re-render the entire list whenever any change is detected, even if only one item was modified. This approach can be highly inefficient, particularly when dealing with large lists, as unnecessary DOM updates can degrade performance.

For example, in the earlier versions of Angular, you might write something like this:

htmlCopy code<div *ngFor="let item of items">
  <item-card [item]="item"></item-card>
</div>

When Angular detects any change in the items array, it might remove and recreate the DOM elements for every single item, even if only one element has changed. This leads to performance issues, especially in scenarios where the data set is large, or frequent updates occur.

The Solution: Track by in @for Loop

The track function in Angular 17-18 is an enhancement of the trackBy functionality previously available with the *ngFor directive. It allows Angular to uniquely identify each item in a list by a specific property, usually an ID or a unique identifier, to optimize the update process.

Here’s how the new syntax looks:

htmlCopy code@for (item of items; track item.id) {
  <item-card [item]="item"></item-card>
}

In this example, the track function tells Angular to use item.id as the unique identifier for each item in the list. This means that when an update occurs in the items array, Angular can compare the IDs and determine which items have changed. Instead of re-rendering the entire list, Angular will only update the specific item that changed, leaving the rest of the list untouched.

Why Is the track Function Mandatory in Angular 17-18?

With Angular 17-18, the track function becomes a mandatory part of the @for loop because it plays a critical role in improving application performance and efficiency.

1. Prevents Unnecessary DOM Manipulation

Without the track function, Angular has no way of knowing which item in the list corresponds to which DOM element. As a result, any change in the list could trigger Angular to rebuild the entire DOM structure for that list. This is both inefficient and can cause performance bottlenecks, especially in applications that handle large datasets or frequent updates.

By using the track function, Angular can identify which items have changed based on their unique identifier (such as item.id) and update only those specific DOM elements. This minimizes unnecessary re-renders and improves the responsiveness of your application.

2. Ensures Stability During List Updates

In addition to performance optimization, the track function helps maintain stability in the UI. For example, imagine you are displaying a list of items with input fields or other interactive elements. Without proper tracking, Angular might re-render the entire list, causing users to lose their focus or unsaved input. The track function ensures that only the relevant DOM elements are updated, preserving the state of other elements.

3. Required for Complex Data Binding

Angular applications often involve complex data binding, where each item in a list might have associated events, classes, or other dynamic properties. The track function allows Angular to maintain consistent bindings across updates by ensuring that the same DOM elements are reused for unchanged items. This is particularly important when working with forms, animations, or other dynamic interactions.

How the track Function Works: A Closer Look

In the @for loop, the track function is used to define a unique identifier for each item in the collection. This identifier can be any property that uniquely represents the item, though it is most commonly an ID.

For example, consider the following list of courses:

typescriptCopy codecourses = [
  { id: 1, name: 'Angular Basics', level: 'Beginner' },
  { id: 2, name: 'Advanced Angular', level: 'Expert' },
  { id: 3, name: 'Angular for Enterprise', level: 'Intermediate' },
];

Using the @for loop with track:

htmlCopy code@for (course of courses; track course.id; let index = $index) {
  <course-card [course]="course" [index]="index"></course-card>
}

Here, Angular uses the id property of each course to track the items. If you were to add, remove, or update a course, Angular would compare the IDs to determine which courses have changed and only update the necessary DOM elements.

Without the track function, Angular would not be able to make this comparison and would re-render the entire list, causing potential performance issues and breaking any in-progress interactions within the list.

What Happens When the track Function Is Missing?

If you omit the track function, Angular will default to tracking items by their object references. This means that Angular will compare the entire object to check for changes. While this works for small lists or lists where objects are not frequently modified, it can lead to performance degradation in larger applications.

For example:

 @for (course of courses) {
<course-card [course]="course"></course-card>
}

In this case, if the courses array is modified (e.g., a course is added or removed), Angular may re-render the entire list, even if only one course has changed. This can lead to slow rendering times, increased memory usage, and a poor user experience.

Best Practices for Using the track Function

  1. Always Use Unique Identifiers: Ensure that the property you use with track is a truly unique identifier, such as an ID. Avoid using properties that might change over time, such as names or titles.
  2. Use for Large Lists: The track function is particularly important when working with large lists. Even for smaller lists, it’s a good habit to include it to ensure optimal performance as your application scales.
  3. Test Performance with and without track: In some cases, especially for small, static lists, you might not notice a significant performance difference. However, as the complexity of your list increases, the benefits of using track will become more apparent. Always test your application’s performance to identify potential bottlenecks.

Instead of simple track course.id you can use the tracking function defined in component.ts file.

For example in app.component.ts:

trackCourse(index: number, course: Course) {
return course.id;
}

And in app.component.html:

<div class="courses">
@for (course of courses; track trackCourse; let index = $index; let count = $count;
let first = $first; let even = $even; let odd = $odd) {

<h1>Count: {{count}}</h1>
<course-card
(courseSelected)="onCourseSelected($event)"
[index]="index"
[course]="course"
[class.is-first]="first"
[class.is-last]="$last"
[class.is-even]="even"
[class.is-odd]="odd"
/>
}
@empty {
<h1>No courses found!</h1>
}
</div>

But in general you should prefer using simplified notation with track course.id.

But what should we do if we don't have and unique id or value in the list?
For example, if we have just a list of strings, we should use as track course itself, string element itself.

As a last resort if there even strings in the loop don't have unique values you can use plain $index for track functions in Angular 17-18 like: track $index (without using variable for $index). This solution is not optimised and good one but at least it will help us to avoid the compilation error about absense of track function on @for loop in Angular last versions.

Conclusion

This track function in Angular helps to diff the previous and current list and optimize the page just changing that part of list that should be changed (which were changed) but not rerender the whole list again and again.

The track function in Angular 17-18’s @for loop is a mandatory and powerful tool that plays a crucial role in optimizing how Angular handles list rendering and updates. By providing Angular with a unique identifier for each item, the track function prevents unnecessary DOM manipulations, improves performance, and ensures that the UI remains stable during updates.

For developers, using the track function should be a standard practice when working with lists in Angular. It not only enhances application performance but also ensures that the user experience remains smooth and responsive, even as the size of your data grows.

As Angular continues to evolve, the introduction of mandatory features like the track function demonstrates the framework’s commitment to providing developers with efficient, powerful tools to build fast and scalable web applications.

Leave a Reply

Your email address will not be published. Required fields are marked *