Prevent loss of focus and reconstruction of elements in your *ngFor on collection change with trackBy
Note: “change the collection-data” means to replace the collection with new objects and not just modifying the objects in the same collection object.
Let us consider a following example.
Tracking *ngFor on array of items changing every 5 seconds to switch line bullets between English & Spanish in different colors
Find full implementation on Github and play with it on CodePen or StackBlitz
Without trackBy :(
ngFor here is not tracking elements by id or index. When items-collection changes ngFor just destroys and recreates elements for each item in the collection.
Try inputting text in the first set of input boxes available on any of these links [CodePen] or [StackBlitz]
Notice, as the *ngFor items change, the focus and cursor from the input box you were typing in goes away, and you will find you aren’t typing anywhere.
On mobile browsers it is even worse. Every time focus from active input is lost, the soft-keyboard closes
With track by :)
ngFor is tracking each element to its rendering in dom by id, and it just renders the corresponding changes in place using using standard change detection instead of destroying and recreating elements
ngFor with trackBy
Try inputting text in the second set of input boxes available on this these links [CodePen] or [StackBlitz].
Notice, as the ngFor items change, the text, focus and cursor in the active input box stays, and you can continue typing even as the bullets keep changing
Note: If you don’t have id (unique-key) for each data-item in your collection, you can always trackBy index (second argument passed to trackByFn). If you use a field to track by that is not unique across items in your collection, angular will throw an error
Try it out yourself
Why is trackBy so important for Angular?
Angular by default tracks items in a collection by object reference. When we replace the collection with new collection which is not keeping the same objects by reference, Angular can’t keep track of items in the collection even if the objects inside the new collection are same by values, but just clone of previous ones.
Unless trackBy provides a unique id per element in *ngFor iteration, angular will have no knowledge of which items have been removed or added or changed in the new collection.
As a result, Angular needs to remove all the DOM elements that associated with the data items in collection and create them again ( unnecessary DOM manipulations).
We all know DOM manipulations are expensive, and for a collection of (n) items, it’s of order(n). Also on every recreation, any focus from the element is lost posing a big usability problem as user may not understand where and why the cursor / focus went away from active element recreated.
Hence, for performance and usability, prefer using trackBy with *ngFor unless the collection never changes and / or items are expected to lose all state on change and be recreated which is seldom the case.
If you liked this article please click the ❤ below or (clap) on Medium on the left side. It’ll motivate me to write more articles like this, and it’ll help other people discover the article as well.