Angular

Handling Observables with NgFor and the Async Pipe

Now you’ve learned the basics of Angular’s NgFor it’s time to take things up a notch and introduce some Observables. In this article you’ll...

Written by Luci · 2 min read >

Now you’ve learned the basics of Angular’s NgFor it’s time to take things up a notch and introduce some Observables. In this article you’ll learn how to use Observables with Angular’s NgFor directive and the async pipe.

NgFor has a not-so-obvious feature that lets us will help us deal with asynchronous operations – the async pipe. The async pipe takes care of subscribing/unsubscribing to Observable streams for us.

Let’s explore how we can handle NgFor alongside the async pipe to subscribe to an Observable!

Using ngFor

Here’s the data we’ll be using as our source to pass into *ngFor:

interface Pizza {
  id: string;
  name: string;
  price: number;
}

const getPizzas$: Pizza[] = [
  { id: "j8P9sz", name: "Pepperoni", price: 899 },
  { id: "tMot06", name: "Supreme", price: 999 },
  { id: "x9sD3g", name: "Sizzler", price: 899 },
];

And here’s where we introduce NgFor alongside perhaps another local NgForOf variable such as index:

<ul>
  <li *ngFor="let pizza of pizzas; index as i">
    {{ i + 1 }}. {{ pizza.name }}
  </li>
</ul>

But Angular is reactive, this means it’s all about Observables. This pattern of Angular development doesn’t follow an Observable data source pattern. So, let’s bring them in!

ngFor and Async Pipe

For this, we’ll introduce Observable of() from RxJS and demonstrate subscribing to an Observable stream via the async pipe and update our typings:

import { Observable, of } from "rxjs";

const getPizzas$: Observable<Pizza[]> = of([
  { id: "j8P9sz", name: "Pepperoni", price: 899 },
  { id: "tMot06", name: "Supreme", price: 999 },
  { id: "x9sD3g", name: "Sizzler", price: 899 },
]);

🕵️‍♀️ RxJS of() is an Observable creation operator that emits the value we pass in!

Let’s get the getPizzas$ variable into our component:

@Component({
  selector: 'app-root',
  template: `...`
})
export class AppComponent implements OnInit {
  pizzas$: Observable<Pizza[]>;

  constructor() {}

  ngOnInit() {
    this.pizzas$ = getPizzas$;
  }
}

🔭 Tip: it’s common practice to suffix properties that are Observables with a $, such as pizzas$

Our NgFor directive can now use the async pipe to subscribe to the pizzas$ observable:

<ul>
  <li *ngFor="let pizza of pizzas$ | async; index as i">
    {{ i + 1 }}. {{ pizza.name }}
  </li>
</ul>

It’s important to remember that using | async creates a subscription if the source is an Observable. Thankfully, when the component is destroyed the subscription is also managed and unsubscribed for us!

Check out the live StackBlitz example:

NgFor Template and Async Pipe

When we think of NgFor, we should think of NgForOf. Here’s how you can use NgFor with the <ng-template> element using the async pipe:

<ul>
  <ng-template ngFor [ngForOf]="pizzas$ | async" let-pizza let-i="index">
    <li>{{ i + 1 }}. {{ pizza.name }}</li>
  </ng-template>
</ul>

This is the longer syntax using <ng-template> and explains why we use *ngFor with the asterisk, which denotes that it’s a behavioral directive.

Check out the live StackBlitz example:

NgFor + NgIf + Async Pipe

So far we’ve covered some really nice usage of NgFor with the async pipe, but now we’re going to show a common practice of “unwrapping” observables on different levels of the template.

First, using NgIf and the Async Pipe, we can do this:

<div *ngIf="pizzas$ | async as pizzas">
  {{ pizza }}
</div>

Instead of using the async pipe directly with NgFor, we could use NgIf to unwrap our Observable into a pizzas variable.

This would allow us to reuse the variable multiple times inside the template without creating repeat subscriptions:

<div *ngIf="pizzas$ | async as pizzas">
  <p>🍕 {{ pizzas.length }} Pizzas!</p>
  <ul>
    <li *ngFor="let pizza of pizzas; index as i">
      {{ i + 1 }}. {{ pizza.name }}
    </li>
  </ul>
</div>

This also means we can avoid using things like the safe navigation operator ? with NgIf or NgFor.

Check out the live StackBlitz example:

Summary

We’ve covered a lot of ground here using Angular’s NgFor directive and the async pipe.

Starting with static data we then used Observable of() to create an Observable and async pipe it into NgFor.

From there, we looked at how we could potentially use NgIf alongside NgFor (and the rest of our template) to avoid subscribing multiple times to our Observable.

Written by Luci
I am a multidisciplinary designer and developer with a main focus on Digital Design and Branding, located in Cluj Napoca, Romania. Profile

Angular Basics: The CLI and Components

Luci in Angular
  ·   7 min read
0 0 votes
Article Rating
Subscribe
Notify of
guest
1 Comment
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Bulelani Kwebulana
Bulelani Kwebulana
2 years ago

I am having problem with ng*For where my code is like this ngfor=”let p of person”

<h1>p.name</h1>
<h1>p.surname</h1>

It is duplicating I dont know what is the cause.Thanks!

1
0
Would love your thoughts, please comment.x
()
x