Angular Async Pipe vs Subscribe

In Angular, there are generally two common ways of handling and displaying data from asynchronous streams. Either use an async pipe in your template or subscribe to the observable and handle it in the callback function.

This article will explain how both methods work and compare them. We’ll do this by going through examples, making it easy for you to understand the difference between the two methods.

Sounds interesting? Then, keep on scrolling.

Display Data in Angular by Subscribing to an Observable

We’ll start by showing you an example of displaying data from an observable by subscribing to it using the subscribe function.

Creating the Angular Service

Let’s assume we have a service containing a BehaviorSubject handling different names. The service will also provide a function for updating the name and a function to fetch the BehaviorSubject as an observable:

import { Injectable } from "@angular/core";
import { BehaviorSubject, Observable } from "rxjs";

@Injectable({
  providedIn: "root",
})
export class NameService {
  name: BehaviorSubject<string> = new BehaviorSubject("Vinnie Jones");

  constructor() {}

  updateName(name: string) {
    this.name.next(name);
  }

  getName(): Observable<string> {
    return this.name.asObservable();
  }
}
name.service.ts

That’s all that is needed for our service.

Note: We’ll also use the same service in our other example where we use the async pipe.

Updating Our App Component

Next up, we can add the code required in our app component. We need to inject the service into our app component, we’ll do that with the help of the component’s constructor:

constructor(private name: NameService) {
    name.getName().subscribe((name) => (this.currentName = name));
  }
app.component.ts

Then, we’ll add a function for pushing new names into our service:

pushName() {
    this.name.updateName(faker.person.fullName());
  }
app.component.ts

And let’s not forget to add a property for storing the current name inside our app component:

currentName: string = "";
app.component.ts

If you’ve followed the steps properly, your app component should look something like this:

import { Component } from "@angular/core";
import { faker } from "@faker-js/faker";
import { NameService } from "./name.service";

@Component({
  selector: "app-root",
  templateUrl: "./app.component.html",
  styleUrls: ["./app.component.scss"],
})
export class AppComponent {
  currentName: string = "";

  constructor(private name: NameService) {
    name.getName().subscribe((name) => (this.currentName = name));
  }

  pushName() {
    this.name.updateName(faker.person.fullName());
  }
}
app.component.ts

Now we just have to display the name and add a button for generating new names in our HTML:

<h1>{{ currentName }}</h1>
<button mat-raised-button color="primary" (click)="pushName()">
  Show me another name
</button>
app.component.html

Result

If you now run your application, you should be able to test it out by clicking on the button and seeing the name changing:

Subscribe to Observable example result

Display Data in Angular using the Async Pipe

Let’s create the same example as the one above, but this time by using the Angular async pipe instead of subscribing to the observable.

We’ll start by removing some stuff from our app component:

import { Component } from "@angular/core";
import { faker } from "@faker-js/faker";
import { NameService } from "./name.service";

@Component({
  selector: "app-root",
  templateUrl: "./app.component.html",
  styleUrls: ["./app.component.scss"],
})
export class AppComponent {
  currentName: string = ""; //REMOVE

  constructor(private name: NameService) {
    name.getName().subscribe((name) => (this.currentName = name)); //REMOVE
  }

  pushName() {
    this.name.updateName(faker.person.fullName());
  }
}
app.component.ts

We also need to make our injected service public and rename it to nameService (The renaming is because name is a reserved keyword in Typescript):

import { Component } from "@angular/core";
import { faker } from "@faker-js/faker";
import { NameService } from "./name.service";

@Component({
  selector: "app-root",
  templateUrl: "./app.component.html",
  styleUrls: ["./app.component.scss"],
})
export class AppComponent {
  constructor(public nameService: NameService) {}

  pushName() {
    this.nameService.updateName(faker.person.fullName());
  }
}
TypeScript

Next, we can call the function getName in the service from our HTML, using the async pipe:

<div>
  <h1>{{ nameService.getName() | async }}</h1>
  <button mat-raised-button color="primary" (click)="pushName()">
    Show me another name
  </button>
</div>
HTML

Result

As you can see, when you run the application, you get the same result as when we ran the previous example:

Handling Observables using Angular Async Pipe example result

Async Pipe vs Subscribing to Observables

The decision on when to use the async pipe or subscribing to an observable depends on the specific requirements and complexity of your Angular application.

Let’s go through the benefits of both methods and hopefully, you’ll know which method suits your application requirements best.

Benefits of Using the Async Pipe

  1. Simple Data Binding: For scenarios where you need to bind Observables directly to your template, especially when rendering data without extensive processing, the async pipe is a convenient choice.
  2. Minimizing Boilerplate: When you want to reduce boilerplate code and simplify your component logic, the async pipe offers a cleaner and more concise solution.
  3. Avoiding Memory Leaks: If memory management is a concern, and you want to ensure that subscriptions are automatically cleaned up, the async pipe is the safer option.

Benefits of Subscribing to an Observable

  1. Complex Data Transformation: When you need to perform complex data transformations, filtering, or combining data from multiple Observables before rendering it, subscribing to observables allows for greater flexibility and control.
  2. Multiple Subscriptions: If your component needs to manage multiple subscriptions and perform different actions based on the data emitted from each Observable this method may be more suitable.
  3. Custom Error Handling: In cases where you require custom error handling or need to perform side effects like logging, this method provides more control.

Conclusion

In conclusion, there are benefits to both using the async pipe and subscribing to an observable.

By going through the same example with both methods, we can conclude that the async pipe is recommended over subscribing to an observable if the requirement is just to show the data.

If your application has the requirements of fetching data from an observable and then transforming and calculating values dependent on the input, the subscribe method is much more suitable.


Hopefully, you enjoyed scrolling through this article. If you’re more interested in Angular, check out our other articles!

Leave a Comment