Angular Pipes (built-in: uppercase, lowercase, currency, date, percent, titlecase, slice; creating custom pipes)

Pipes transform a value for display without changing the underlying data: use the | operator with built-in pipes like uppercase, date and currency, and write your own with @Pipe.

10 min read · 9 cards · 2 checks

Read in: English · हिन्दी · ગુજરાતી


Theory

Format for the eye, not the data

FestConnect stores an event fee as the number 49.5 and a date as a raw timestamp. But users should SEE 'Rs 49.50' and '12/07/2026'. You could store formatted strings, but that corrupts the data (you cannot do math on 'Rs 49.50').

The right approach: keep the raw data, and TRANSFORM it only when DISPLAYING. Angular's tool for this is the pipe: a display-only formatter you apply in the template with the | operator. This short lesson covers built-in pipes and how to write your own, so FestConnect's data stays clean while looking polished.

Theory

Pipes, formally

A pipe transforms a value in the TEMPLATE for DISPLAY, WITHOUT changing the underlying data. The syntax uses the | operator:

{{ event.name | uppercase }} shows the name in capitals; the stored value is untouched.

Pipes take arguments after a colon and can chain:

  • {{ fee | currency:'INR' }}: format as currency
  • {{ today | date:'dd/MM/yyyy' }}: format a date
  • {{ name | lowercase | titlecase }}: chain two pipes

Common built-in pipes: uppercase, lowercase, titlecase, date, currency, percent, slice, json, and async (which unwraps an Observable or Promise right in the template). The key property: pipes are read-only formatting; the source data never changes.

Practical

Built-in pipes and a custom pipe

// In a template:
// {{ 'garba night' | titlecase }}   -> Garba Night
// {{ 49.5 | currency:'INR' }}       -> currency-formatted fee
// {{ today | date:'dd/MM/yyyy' }}    -> 12/07/2026

// A CUSTOM pipe: @Pipe + PipeTransform
import { Pipe, PipeTransform } from '@angular/core';

@Pipe({ name: 'seatsLabel' })
export class SeatsLabelPipe implements PipeTransform {
  transform(seats: number): string {
    return seats > 0 ? seats + ' seats left' : 'Sold out';
  }
}
// Used in a template:  {{ event.seats | seatsLabel }}
//   350 -> "350 seats left"   0 -> "Sold out"

Theory

Writing a custom pipe

When no built-in pipe fits, write your own:

  • a class decorated with @Pipe({ name: 'seatsLabel' })
  • implementing PipeTransform with a transform(value, ...args) method that returns the transformed value

Then use it in a template like any pipe: {{ event.seats | seatsLabel }}. The custom pipe above turns a seat NUMBER into a friendly LABEL ('350 seats left' or 'Sold out') purely for display.

Comparing to React: React has no pipe syntax; you would call a plain JavaScript function or write an expression in JSX ({seatsLabel(event.seats)}). Angular's pipe is a declarative, reusable formatting tool built into the template language, cleaner for repeated formatting, and a distinctive Angular feature.

Quiz

What does a pipe do to the underlying data when it formats a value like {{ price | currency }}?

  1. It permanently converts the stored price to a formatted string
  2. Nothing: a pipe transforms the value only for DISPLAY; the underlying data is unchanged
  3. It deletes the original value
  4. It moves the value to a new variable
Show the answer

Nothing: a pipe transforms the value only for DISPLAY; the underlying data is unchanged

A pipe is a DISPLAY-only transform: {{ price | currency }} shows the price formatted as currency in the template, but the underlying price value in the class stays exactly as it was (still the number you can do math on). Option A misunderstands pipes as mutating data, which they never do, that is the whole point (keep clean data, format only for the eye). Option C and D invent destructive behaviour. This separation, raw data in the class, formatting in the template via pipes, is why you should format with pipes rather than storing pre-formatted strings: the data stays usable and the display stays polished.

Think first

Why not just store 'Rs 49.50'?

It would be simpler to store the fee as the string 'Rs 49.50' and display it directly. Why is keeping the raw number 49.5 and using a currency pipe the better design? Then tap.

Show the answer

Because storing 'Rs 49.50' as a string DESTROYS the number's usefulness. You could no longer add fees, sort events by price, apply a discount, or total a bill, because 'Rs 49.50' is text, not a number. Keeping the raw 49.5 preserves all that math, and the currency PIPE formats it for display only when shown, so the data stays computable AND looks right. The same logic applies to dates (store a real date, display with the date pipe) and any formatted value. This is a general principle beyond Angular: separate DATA from PRESENTATION, keep data in its most useful raw form, and format at the edge, for the eye. Pipes are Angular's clean mechanism for that separation.

Watch out

Pipe traps

Storing formatted strings: keep raw data (numbers, dates); format with pipes for display.

Expecting a pipe to change data: pipes are display-only; the source value is unchanged.

Custom pipe without PipeTransform: implement PipeTransform and the transform() method, or it will not work.

Wrong pipe arguments: arguments follow a colon ({{ x | date:'short' }}); check each pipe's expected arguments.

Heavy work in a pipe: pipes run on change detection; keep transform() light.

Theory

Display polished; now capture input properly

Pipes format what FestConnect shows. The other half is what it COLLECTS: forms. Angular offers two form approaches, template-driven (simple, using ngModel) and reactive (powerful, defined in the class), plus validation. The next lesson covers both and when to use each. Then the final Angular lesson, services and dependency injection with HttpClient, connects FestConnect to a real REST API. Forms next.

Summary

Key takeaways

  • A pipe transforms a value for DISPLAY only (via the | operator); the underlying data is unchanged.
  • Syntax: {{ value | pipeName }}; arguments after a colon ({{ fee | currency:'INR' }}); pipes chain.
  • Built-in pipes: uppercase, lowercase, titlecase, date, currency, percent, slice, json, async.
  • Custom pipe: a class with @Pipe({name}) implementing PipeTransform's transform(value, ...args) method.
  • Keep raw data (numbers, dates) and format with pipes, rather than storing pre-formatted strings.
  • Separating data from presentation keeps values computable and display polished.
  • Memory hook: pipes format for the eye with |, never touching the data.

Study this properly

This page is the lesson to read. In Gri-Learn the same topic is a graded deck: the self-checks are scored and your weak topics are tracked. Free to start.

Start this topic

Already have an account? Sign in

More from Fundamentals of Angular

Gri-Learn · syllabus-mapped B.C.A. lessons in English, Hindi and Gujarati