Formatting Values in Templates with Pipes

In Angular, pipes provide a mechanism for converting values before they are rendered. They take input data and reshape it into the format you want to show to the user.

Calling a method directly inside a template to format data is a common mistake that can degrade performance. Any time change detection runs, that method executes again, which can become expensive. Pipes are the recommended solution for this kind of display transformation.

The pipe operator (|) is what you use in your component template. It receives the value on its left side and passes it to the pipe function on the right. The pipe then returns the transformed value that gets displayed.

Angular ships with a set of built-in pipes that cover common formatting needs. When those don't fit your requirements, you also have the option to build a custom pipe to produce exactly the output you need.

A live example is available on StackBlitz for you to explore.

Applying the Built-in Currency Pipe

Let's imagine you have a collection of job postings, each listing a salary. This data structure is a good starting point to see how a pipe works.

salaryRanges = [
    {
      title: 'developer',
      salary: 90000,
    },
    {
      title: 'nbaPlayer',
      salary: 139883,
    },
    {
      title: 'doctor',
      salary: 72000,
    },
  ];
Enter fullscreen mode Exit fullscreen mode
<ul>
  <li *ngFor="let profesional of salaryRanges">
    {{ profesional.title }}
    {{ profesional.salary }}
  </li>
</ul>
Enter fullscreen mode Exit fullscreen mode

To display these salaries with a currency symbol and decimal places, you can use the currency pipe. In its default state, it applies the USD format to the value it receives.

<ul>
  <li *ngFor="let profesional of salaryRanges">
    {{ profesional.title }}
    {{ profesional.salary | currency }}
  </li>
</ul>
Enter fullscreen mode Exit fullscreen mode

The result of this transformation in the template would be:

developer $90,000.00
nbaPlayer $139,883.00
doctor $72,000.00
Enter fullscreen mode Exit fullscreen mode

What if you need to show the salary in a different currency, say euros, instead of the default US dollar? No built-in pipe can handle a conversion on its own. To tackle a requirement like this, you'll need to extend Angular's functionality.

It's time to build a custom pipe.

Building Your Own Custom Pipe

A custom pipe is defined by creating a regular class that implements the PipeTransform interface. The core of this is the transform method, where you define your logic.

Here, the initial convertExchange pipe takes a salary value and computes the result by dividing the input by 55.

import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
  name: 'convertExchange'
})
export class ConvertToExchange implements PipeTransform {
  transform(value: any, args?: any): any {
    return value / 55
  }
}

Enter fullscreen mode Exit fullscreen mode

Remember to declare the custom pipe in your module so Angular recognizes it.

Pipes can be chained to combine their effects. By using currency after convertExchange, the custom pipe handles the calculation, while the built-in one is responsible for the final formatting.

{{ professional.salary | convertToExchange | currency }}



Done the money shows with the format and the conversion rate.



```html
developer $1,636.36
nbaPlayer $2,543.33
doctor $1,309.09
Enter fullscreen mode Exit fullscreen mode

This custom pipe already lets you manipulate data. But what if you want it to be more adaptable, so you can easily switch between USD and EURO in the future without rewriting code?

The first step is to set up an object that stores currency keys and their corresponding values.

const currencyValues = {
  USD: 55,
  EURO: 75,
};
Enter fullscreen mode Exit fullscreen mode

Then, you'll update the transform method to accept a second parameter for the currency name. A separate helper method inside the class will look up and return the correct exchange rate from your object.

Here's the updated code:

import { Pipe, PipeTransform } from '@angular/core';
const currencyValues = {
  USD: 55,
  EURO: 75,
};

@Pipe({
  name: 'convertToExchange'
})
export class ConvertToExchange implements PipeTransform {
  transform(value: any, currency: string): any {
    return value / this.getCurrencyValue(currency);
  }

  getCurrencyValue(currency) {
    return currencyValues[currency] | 1;
  }
}
Enter fullscreen mode Exit fullscreen mode

You've made your pipe dynamic. To use it in the template, you pass the argument to the pipe after a colon (:). In this example, you specify either 'USD' or 'EURO'.

This version of convertToExchange performs the calculation based on the currency you select and formats the result appropriately. The rendered output would look like this:

  {{ profesional.salary | convertToExchange: 'USD' | currency }}
Enter fullscreen mode Exit fullscreen mode

The following is the final display you can expect to see:

developer $1,636.36
nbaPlayer $2,543.33
doctor $1,309.09
Enter fullscreen mode Exit fullscreen mode

Turning It Into a Dynamic Converter

To let the user select which currency to convert to, we add a dropdown listing the available options.

<select (change)="changeTo($any($event.target).value)">
  <option value="USD">USD</option>
  <option value="EURO">EURO</option>
  <option selected>DOP</option>
</select>

Inside the component, a new property, currentCurrency, is initialized with the value DOP. This property will be updated whenever the user makes a new selection.

 currentCurrency = 'DOP';
changeTo(currency) {
    this.currentCurrency = currency;
  }

In the template, we pass currentCurrency as the argument to the pipe.

<li *ngFor="let profesional of salaryRanges">
    {{ profesional.title }}
    {{ profesional.salary | convertToExchange: currentCurrency | currency }}
  </li>

Once a different currency is selected from the dropdown, the conversion is automatically recalculated. The UI immediately reflects the updated value.

Final version

Wrapping Up

Pipes are a versatile feature in Angular, and the official documentation offers many more examples and advanced use cases worth exploring.

Explore more about Pipes: https://angular.io/guide/pipes

Feel free to experiment with the completed implementation here:

https://stackblitz.com/edit/angular-ivy-opaevp?file=src%2Fapp%2Fapp.component.html

Cover image by T K on Unsplash