If you're a budding Angular developer, you've probably come across ngFor
, one of Angular's built-in directives that can turn your complex tasks into a walk in the park.
Not only can it streamline your application's flow and make your coding journey significantly smoother, but thanks to its ability to let you loop through items in an array directly within your templates, it can help keep your code clean, concise, and easy to read.
But how do we use it?
Well, good news! In this beginner tutorial, we'll take a deep dive into Angular's ngFor
directive and I'll teach you how it works.
Everything from its fundamental mechanics and applications to common errors and their solutions. So whether you're looking to stripe a table, find the index of a list element, or loop through static numbers and objects, I've got you covered.
And we won't stop there. We'll also take a look at how ngFor
behaves during dynamic list modifications and delve into more complex tasks, such as nesting ngFor
to display objects within objects.
Armed with this knowledge, you'll not only ace your Angular development projects, but you'll save hours of debugging time by avoiding common pitfalls.
You can think of this guide as your one-stop solution to mastering ngFor
in Angular!
Let’s get started.
ngFor
is a powerful built-in directive in Angular that simplifies the process of rendering dynamic lists within your HTML templates.
It lets you loop through items in an array, creating a new HTML element for each item according to the template you define. This not only makes your code cleaner and more concise but also enhances its maintainability by reducing redundancy.
The ngFor
directive operates by duplicating a block of HTML for each item in an array. You use the let item of items syntax to instruct Angular to create a new instance of the block for every item in your collection.
For example
<li *ngFor="let item of items">{{item}}</li>
In this code snippet, ngFor
is applied to a <li>
element, generating a new list item for each item in the items array. While the * symbol before ngFor
signifies a shorthand that Angular uses to expand this into a more complex HTML structure behind the scenes, allowing you to maintain a clean and readable template.
This directive is not limited to simple data types; it can efficiently handle arrays of complex objects. For instance, consider an array of users, where each user has a name and an email.
For example
Let's say I have an array of users
, where each user
is an object with properties name
and email
. Here's how I might use ngFor
to display this data:
<li *ngFor="let user of users">
{{user.name}} ({{user.email}})
</li>
Each user’s name and email are displayed in separate list items, demonstrating ngFor
’s capability to iterate over data structures and embed dynamic content within HTML effortlessly.
Mastering ngFor
allows you to dynamically generate content tailored to the needs of your application, significantly reducing code redundancy and enhancing the flexibility and readability of your Angular templates.
By understanding the basics and leveraging the directive's full potential, you can efficiently manage dynamic lists and complex data structures, paving the way for more advanced Angular development techniques.
Alright, let's look at some applications for this directive.
We’ve talked about a few options already but we’ve added them again below along with other features, so you can have all of these in one place.
One of the basic uses of ngFor
is to iterate over an array. Imagine I have an array of names and we want to display each one in a list.
Using ngFor
, I can do this with minimal coding.
let names = ['John', 'Jane', 'Amy', 'Emma'];
<div *ngFor="let name of names">
{{name}}
</div>
In this example, ngFor
loops over the names array and assigns each value to the variable name
which is then displayed in the div.
Arrays in real-world applications often contain objects, and ngFor
can handle this too.
For example
Let's say I have an array of user objects, where each object has properties like id
and username
:
let users = [{id: 1, username: 'john'}, {id: 2, username: 'jane'}];
<div *ngFor="let user of users">
ID: {{user.id}}, Name: {{user.username}}
</div>
Here, ngFor
loops over each user object in the user's array. It then accesses the id
and username
properties of each user object and displays them.
Sometimes, we need to display the index of each item along with its value. With ngFor
, I can easily get the index of the current item in the loop like so:
let colors = ['Red', 'Green', 'Blue'];
<div *ngFor="let color of colors; let i = index">
{{i+1}}. {{color}}
</div>
The i=index
part of the code assigns the current index to i
which can then be used in the template.
Stripping a table can improve readability by visually separating each row, and ngFor
offers the even
and odd
variables to make this option nice and straightforward:
let items = ['Item1', 'Item2', 'Item3', 'Item4'];
<tr *ngFor="let item of items; let i = index; let e = even" [class.even-row]="e">
<td>{{i+1}}</td><td>{{item}}</td>
</tr>
Here, I use ngFor
in combination with Angular's class binding syntax. When the row is even (even-row
), I apply a different CSS class, which could, for example, change the row's background color.
When dealing with collections, it's not uncommon to require special handling for the first and last items, but with ngFor
, you can easily identify the first and last elements in your iteration:
let teams = ['Team1', 'Team2', 'Team3'];
<div *ngFor="let team of teams; let isFirst = first; let isLast = last">
<p>{{team}} - First: {{isFirst}} - Last: {{isLast}}</p>
</div>
isFirst
and isLast
variables directly give you Boolean values indicating whether the current item is the first or last in the array.
Your lists won't always be static, and you might need to add or remove items. Here's how ngFor
handles dynamic list modifications:
let fruits = ['Apple', 'Banana', 'Cherry'];
// Adding an element
fruits.push('Orange');
// Removing an element
let index = fruits.indexOf('Cherry');
if (index !== -1) {
fruits.splice(index, 1);
}
<div *ngFor="let fruit of fruits">
{{fruit}}
</div>
As soon as the fruits
array changes, ngFor
updates the DOM to match. This makes managing dynamic lists simple and efficient.
ngFor
can also be used to generate a loop of static numbers, which is useful for cases where you want to display a certain number of elements or create pagination:
<div *ngFor="let number of '.repeat(5).split(','); let i = index">
{{i+1}}
</div>
In this example, this code will display numbers from 1 to 5.
ngFor
isn't just for arrays. It can also loop over the properties of an object:
let user = {id: 1, name: 'John', age: 30};
<div *ngFor="let item of user | keyvalue">
{{item.key}}: {{item.value}}
</div>
Notice the keyvalue
pipe here, as this transforms our object into an array of key-value pairs that ngFor
can loop over.
Finally, ngFor
can also support nesting - like a loop within a loop. This is useful for dealing with complex data structures:
let users = [
{
name: 'John',
skills: ['Java', 'Angular', 'Python']
},
{
name: 'Jane',
skills: ['C#', 'React', 'Node']
}
];
<div *ngFor="let user of users">
{{user.name}}
<ul>
<li *ngFor="let skill of user.skills">
{{skill}}
</li>
</ul>
</div>
This code will loop over each user, and then loop over each of their skills, displaying them in a nested list.
Phew! So that was a quick whirlwind tour of the various applications of Angular's ngFor
directive, from simple loops to dynamic list management, and from indexing to nested looping.
With a grasp of these concepts, you'll have a powerful toolset for front-end development at your disposal.
Even with a solid understanding of ngFor
, you might encounter occasional errors, which is ok. It's an essential part of the development and learning process!
To help you save some time and figure out what went wrong, here are some common ngFor
- related errors and their solutions:
This is a common mistake made by JavaScript developers transitioning to Angular, as they often use 'in' for looping in JavaScript.
But in the ngFor
directive, we use 'of', and so using 'in' would throw an error in Angular.
// Incorrect
<div *ngFor="let item in items">
{{item}}
</div>
// Correct
<div *ngFor="let item of items">
{{item}}
</div>
ngFor
can't iterate through non-iterable objects. If you attempt to do so, Angular throws an error.
let nonIterableObject = 10;
// Throws error: Cannot find a different supporting object '10' of type 'number'
<div *ngFor="let number of nonIterableObject">
{{number}}
</div>
In this example, I try to iterate over a number, which is non-iterable, so make sure to use only iterable objects, like arrays or strings, with ngFor
.
Modifying the index variable in ngFor
is a bad practice and could lead to unexpected results.
This is because Angular's ngFor
uses the index only for read operations, and making changes to it won't affect the original array.
// Incorrect and ineffective
<div *ngFor="let item of items; let i = index">
{{i++}}. {{item}}
</div>
This error occurs if we try to access a property of an undefined object in our array during looping.
let users = [{name: 'John'}, {name: 'Jane'}, null, {name: 'Emma'}];
// Throws error: Cannot read property 'name' of null
<div *ngFor="let user of users">
{{user.name}}
</div>
Ensure each object in your array is defined and has the properties you're trying to access.
This isn't an exhaustive list of ngFor
errors. Just remember that debugging is a part of the development process. Each error message gives you a direction to find the problem in your code. So, consider them your guides, not your enemies!
Angular uses a strategy called trackBy
to keep track of each element in an array when using the ngFor
directive, especially when the array is updated by adding or removing elements.
This is particularly important for performance optimization and to maintain the state of DOM elements, such as input focus or component states.
Why?
Well, when you use ngFor
without a trackBy
function, Angular tracks elements using object identity. This means that every time the array changes, Angular performs a DOM manipulation by removing elements and reinserting them, even if the actual object references haven’t changed.
This can lead to performance issues and unwanted behavior (like losing focus on an input element).
Truthfully, rendering lists is never as simple as just using the ngFor
directive.
There are a lot of optimizations you may need to take to render a list. From my experience, one of the best ways to optimize performance and avoid unnecessary DOM updates is by providing a trackBy
function.
This function then tells Angular how to identify a unique identifier for each item. If the unique identifier hasn't changed, Angular will keep the corresponding DOM element intact.
Let’s look at an example.
You need to define a function in your component that takes two arguments:
The function should return a unique identifier for each item, like so:
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
template: `
<ul>
<li *ngFor="let item of items; trackBy: trackById">
{{ item.id }} - {{ item.name }}
</li>
</ul>
<button (click)="addItem()">Add Item</button>
`
})
export class AppComponent {
items = [
{ id: 1, name: 'Item 1' },
{ id: 2, name: 'Item 2' }
];
trackById(index: number, item: any): number {
return item.id; // Use unique identifier as a tracking function
}
addItem() {
this.items.push({ id: this.items.length + 1, name: `Item ${this.items.length + 1}` });
}
}
So what's happening here?
Well, in this example:
trackById
function returns the id
property of each item. Since the id
is unique for each item, Angular uses it to track the item's identity across updatesHopefully, this guide has shined a light on how and when to use this directive.
The ability to manage and manipulate collections of data effectively is paramount, and this is where ngFor
shines, but remember to also add in trackBy
to help run it even smoother.
All that’s left now is for you to try this out in your own code. It might seem simple, but mastering ngFor
and Angular as a whole can open up a world of opportunities.
Employers are always on the lookout for developers who can build efficient, scalable web applications, and Angular is often their framework of choice. So keep learning, keep coding, and who knows where your skills will take you next!
If you want to learn more about this directive, and want a deeper understanding of Angular, then check out my complete Angular Bootcamp course.
I guarantee it's the only course you need to learn Angular, build enterprise-level applications from scratch (including a massive video sharing application), and be able to get hired as an Angular Developer this year.
Even better? When you join, you’ll also get access to me and 1,000s of other students, and working developers, inside the ZTM Discord.
Ask questions, help others, or just network with other devs and other tech professionals.
With a 30 day money back guarantee, you’ve got nothing to lose.
Happy coding!