Angular

Pipes

15 Questions

Pipes are simple functions used in templates to transform displayed values without changing the underlying data. They accept an input value and return a transformed output using the pipe | operator. You can use built-in pipes or create custom pipes for your specific needs. Pipes are applied directly in template expressions inside interpolation or property bindings.
<!-- Built-in pipes -->
<p>{{ 'hello world' | uppercase }}</p>        <!-- HELLO WORLD -->
<p>{{ today | date:'fullDate' }}</p>           <!-- Wednesday, March 25, 2026 -->
<p>{{ price | currency:'USD' }}</p>            <!-- $29.99 -->
<p>{{ user | json }}</p>                       <!-- {"name":"John"} -->
Angular provides built-in pipes like DatePipe, CurrencyPipe, DecimalPipe, AsyncPipe, JsonPipe, and more. You can also chain multiple pipes and pass parameters using colons.

Why it matters: Tests understanding of Angular pipe fundamentals. Shows you know template transformation basics.

Real applications: Date formatting in user profiles, currency display in shopping carts, text transformation in headers, debugging with JSON pipes.

Common mistakes: Developers don't know pipes exist using manual transformations. They put pipe logic in components instead of templates. They forget pipes don't modify underlying data.

The DatePipe formats a date value according to locale rules and a format string. It accepts a Date object, a number (timestamp), or an ISO date string as input. You can use predefined formats like 'short', 'medium', or 'fullDate', or create custom format strings. It is one of the most commonly used pipes in Angular applications.
<p>{{ myDate | date }}</p>                    <!-- Mar 25, 2026 -->
<p>{{ myDate | date:'short' }}</p>             <!-- 3/25/26, 10:30 AM -->
<p>{{ myDate | date:'fullDate' }}</p>          <!-- Wednesday, March 25, 2026 -->
<p>{{ myDate | date:'yyyy-MM-dd HH:mm' }}</p> <!-- 2026-03-25 10:30 -->
<p>{{ myDate | date:'EEEE' }}</p>              <!-- Wednesday -->

// In the component
export class AppComponent {
  myDate = new Date();
}
Common format tokens: y (year), M (month), d (day), H (hour 24h), h (hour 12h), m (minute), s (second). You can also pass timezone and locale parameters for internationalization.

Why it matters: Tests understanding of date formatting in Angular. Shows you know locale-aware formatting.

Real applications: User profile timestamps, event dates in calendar apps, post creation dates in social media, timezone-specific deadlines.

Common mistakes: Developers hardcode date strings instead of using DatePipe. They don't use locale parameters for international apps. They don't know timezone parameter exists.

The CurrencyPipe formats a number as a currency string based on the locale and a currency code. It accepts parameters for currency code, display format, and digit formatting. You can show currencies as symbols ($, €, £), codes (USD, EUR), or narrow symbols. The pipe automatically handles thousands separators and decimal places based on locale rules.
<p>{{ 1234.5 | currency }}</p>               <!-- $1,234.50 -->
<p>{{ 1234.5 | currency:'EUR' }}</p>          <!-- €1,234.50 -->
<p>{{ 1234.5 | currency:'GBP':'symbol' }}</p> <!-- £1,234.50 -->
<p>{{ 1234.5 | currency:'USD':'code' }}</p>   <!-- USD1,234.50 -->
<p>{{ 99.9 | currency:'INR':'symbol':'1.0-0' }}</p> <!-- ₹100 -->
Parameters: currencyCode (ISO 4217 like USD, EUR), display ('code', 'symbol', or 'symbol-narrow'), and digitsInfo for controlling decimal precision. Default currency is based on the application's locale setting.

Why it matters: Tests understanding of currency formatting. Shows you know formatting with parameters.

Real applications: Product prices in e-commerce, invoice totals in accounting software, payment amounts in banking apps, multi-currency support.

Common mistakes: Developers use wrong ISO currency codes. They don't format decimal places properly. They forget to specify currency code defaulting to USD.

The AsyncPipe subscribes to an Observable or Promise and returns the latest emitted value directly in the template. It automatically unsubscribes when the component is destroyed, preventing memory leaks. This eliminates the need for manual subscribe and unsubscribe patterns in your component. It also works perfectly with OnPush change detection because it calls markForCheck() automatically.
@Component({
  selector: 'app-users',
  template: '<ul><li *ngFor="let user of users$ | async">{{ user.name }}</li></ul>'
})
export class UsersComponent {
  users$: Observable<User[]>;

  constructor(private http: HttpClient) {
    this.users$ = this.http.get<User[]>('/api/users');
  }
}
AsyncPipe handles subscription, value extraction, and cleanup automatically. It marks the component for change detection when new values arrive, making it the preferred way to handle observables in templates.

Why it matters: Tests understanding of Observables and async patterns. Shows you know memory management with pipes.

Real applications: Loading user data from API, real-time notifications, WebSocket connections, HTTP responses in components.

Common mistakes: Developers manually subscribe to Observables creating memory leaks. They forget async pipe auto-unsubscribes. They don't use it with OnPush change detection.

Create a class decorated with @Pipe that implements the PipeTransform interface and its transform method. The pipe name in the decorator is what you use in templates with the | operator. The transform method receives the input value as the first argument and any parameters as subsequent arguments. Custom pipes are pure by default, meaning they only recalculate when the input reference changes.
@Pipe({ name: 'truncate' })
export class TruncatePipe implements PipeTransform {
  transform(value: string, limit: number = 50, trail: string = '...'): string {
    if (!value) return '';
    return value.length > limit
      ? value.substring(0, limit) + trail
      : value;
  }
}

// Usage in template
// <p>{{ longText | truncate:30:'...' }}</p>
Custom pipes must be declared in a module's declarations array or marked as standalone before use. Additional arguments in transform map to colon-separated parameters in the template.

Why it matters: Tests understanding of custom pipe creation. Shows you can extend Angular with reusable transformations.

Real applications: Text truncation for summaries, phone number formatting, text slug generation, file size formatting (KB, MB, GB).

Common mistakes: Developers don't declare pipes in modules. They put complex logic in pipes instead of services. They forget pipes for standalone components need special setup.

A pure pipe (default) only re-evaluates when its input value or parameters change by reference. An impure pipe runs on every change detection cycle, regardless of whether the input changed. Pure pipes are the default and much more performant because Angular can skip them when the input reference has not changed. Set pure: false in the @Pipe decorator to create an impure pipe.
// Pure pipe (default) - efficient, only runs when input reference changes
@Pipe({ name: 'filterPure', pure: true })
export class FilterPurePipe implements PipeTransform {
  transform(items: any[], term: string) {
    return items.filter(i => i.name.includes(term));
  }
}

// Impure pipe - runs on EVERY change detection cycle
@Pipe({ name: 'filterImpure', pure: false })
export class FilterImpurePipe implements PipeTransform {
  transform(items: any[], term: string) {
    return items.filter(i => i.name.includes(term));
  }
}
Pure pipes are more performant and should be used whenever possible. Impure pipes detect changes within objects and arrays but can cause performance issues in large applications.

Why it matters: Tests understanding of pipe performance. Shows you know optimization strategies.

Real applications: List filters use pure pipes for performance, complex calculations might use impure pipes carefully, sorting operations.

Common mistakes: Developers don't know pure vs impure difference. They create impure pipes unnecessarily harming performance. They don't understand reference change requirement.

Pipes can be chained by using multiple pipe | operators on the same expression. Each pipe receives the output of the previous pipe as its input value. The execution order is strictly left to right so the order matters for the final result. This makes it easy to compose multiple transformations in a readable and declarative way.
<!-- Chain pipes: applied left to right -->
<p>{{ birthday | date:'fullDate' | uppercase }}</p>
<!-- Output: WEDNESDAY, MARCH 25, 2026 -->

<p>{{ longText | truncate:100 | lowercase }}</p>

<p>{{ amount | currency:'USD' | slice:0:5 }}</p>

<!-- Order matters -->
<p>{{ 'hello world' | uppercase | slice:0:5 }}</p>  <!-- HELLO -->
<p>{{ 'hello world' | slice:0:5 | uppercase }}</p>  <!-- HELLO -->
The output of each pipe becomes the input of the next pipe in the chain. Chaining is a powerful pattern for combining simple, reusable transformations into complex formatting.

Why it matters: Tests understanding of pipe composition. Shows you know declarative transformations.

Real applications: Converting date to string then truncating, formatting currency then slicing, combining text transformations.

Common mistakes: Developers forget chain order matters. They create monolithic pipes instead of chaining small ones. They don't understand left-to-right execution.

The KeyValuePipe transforms an Object or Map into an array of key-value pairs. This makes it possible to iterate over object properties with *ngFor, which normally only works with arrays. Each item in the result has a key and value property that you can access in the template. It works with both plain JavaScript objects and ES6 Map instances.
@Component({
  selector: 'app-config',
  template: '<div *ngFor="let item of settings | keyvalue">{{ item.key }}: {{ item.value }}</div>'
})
export class ConfigComponent {
  settings = {
    theme: 'dark',
    language: 'en',
    fontSize: 14
  };

  // Also works with Map
  map = new Map([['name', 'Angular'], ['version', '17']]);
}
By default, KeyValuePipe sorts entries alphabetically by key. You can pass a custom comparator function to control the order: {{ map | keyvalue:customCompare }}.

Why it matters: Tests understanding of object iteration patterns. Shows you know working with unordered data structures.

Real applications: Configuration objects display, settings forms, dictionary/map rendering, filter dropdowns from object keys.

Common mistakes: Developers use *ngFor on objects without KeyValuePipe. They don't know it works with Maps. They forget default sorting is alphabetical.

The SlicePipe creates a subset of an array or string, similar to JavaScript's Array.prototype.slice() method. It takes a start index and an optional end index as parameters. You can use it for simple pagination, truncating strings, or displaying a portion of a list. Negative indices count from the end of the array or string.
<!-- Slice an array -->
<li *ngFor="let item of items | slice:0:5">{{ item }}</li>

<!-- Paginate a list -->
<li *ngFor="let item of items | slice:startIndex:endIndex">
  {{ item.name }}
</li>

<!-- Slice a string -->
<p>{{ 'Hello Angular' | slice:6 }}</p>             <!-- Angular -->
<p>{{ 'Hello Angular' | slice:0:5 }}</p>            <!-- Hello -->

<!-- Negative index (from end) -->
<p>{{ 'Hello Angular' | slice:-7 }}</p>              <!-- Angular -->
SlicePipe is a pure pipe so it only recalculates when the input reference or parameters change. It is useful for quick list pagination without writing additional component logic.

Why it matters: Tests understanding of array slicing in templates. Shows you know simple pagination without component code.

Real applications: Displaying first 5 products on homepage, showing featured items, simple pagination without backend, preview lists.

Common mistakes: Developers implement pagination in components instead of using SlicePipe. They don't know it works with negative indices. They create inefficient copy operations.

Pipes accept parameters after a colon : in the template expression. Multiple parameters are separated by additional colons. In the transform method, the first argument is always the piped value and additional arguments map to parameters in order. Default values can be assigned in the method signature so parameters become optional.
<!-- Single parameter -->
<p>{{ today | date:'shortDate' }}</p>

<!-- Multiple parameters -->
<p>{{ price | currency:'EUR':'symbol':'1.2-2' }}</p>

<!-- Custom pipe with parameters -->
@Pipe({ name: 'repeat' })
export class RepeatPipe implements PipeTransform {
  transform(value: string, times: number = 2, separator: string = ' '): string {
    return Array(times).fill(value).join(separator);
  }
}

// Usage: {{ 'Hi' | repeat:3:'-' }}  outputs: Hi-Hi-Hi
The first argument to transform() is the value being piped through. Additional arguments correspond to the colon-separated parameters in the template, making pipes flexible and configurable.

Why it matters: Tests understanding of parameterized transformations. Shows you know creating flexible pipes.

Real applications: Custom formatting pipes, data transformation with options, locale-specific formatting, configurable date/time display.

Common mistakes: Developers create separate pipes for each variation instead of parameterizing. They don't understand default parameter values. They forget parameter order matters.

DecimalPipe formats a number according to locale rules and a digit formatting string. The format follows the pattern minIntegerDigits.minFractionDigits-maxFractionDigits. It is useful for displaying numbers with specific decimal precision like prices, statistics, or measurements. If you do not provide a format string, it uses the default locale formatting.
<p>{{ 3.14159 | number:'1.2-3' }}</p>    <!-- 3.142 -->
<p>{{ 42 | number:'3.0-0' }}</p>          <!-- 042 -->
<p>{{ 1234567 | number }}</p>             <!-- 1,234,567 -->
<p>{{ 0.956 | percent:'1.1-1' }}</p>      <!-- 95.6% -->
The number pipe name is the alias used in templates for DecimalPipe. You can also specify a locale as the second parameter for internationalization support.

Why it matters: Tests understanding of number formatting patterns. Shows you know precision and locale support.

Real applications: Displaying statistics with decimals, formatting sensor measurements, showing financial reports, percentage displays.

Common mistakes: Developers don't know the format pattern syntax. They show excessive decimal places by default. They don't use locale parameter for international apps.

PercentPipe multiplies a number by 100 and formats it as a percentage string with a percent symbol. It accepts a digit formatting string similar to DecimalPipe for controlling decimal precision. The input value should be a decimal like 0.75 which displays as 75%. It is useful for displaying ratios, progress values, or statistics.
<p>{{ 0.259 | percent }}</p>              <!-- 26% -->
<p>{{ 0.259 | percent:'1.1-1' }}</p>      <!-- 25.9% -->
<p>{{ 1 | percent }}</p>                   <!-- 100% -->
<p>{{ 0.5 | percent:'1.0-0' }}</p>        <!-- 50% -->
PercentPipe follows the same digit format pattern as DecimalPipe. You can control the number of decimal places and minimum integer digits with the format parameter.

Why it matters: Tests understanding of percentage display. Shows you know formatting ratios and proportions.

Real applications: Progress bars showing completion percentage, survey results, test score displays, storage usage indicators.

Common mistakes: Developers multiply by 100 manually before using pipe. They use wrong digit format strings. They display 0.75 as 0% instead of 75%.

LowerCasePipe converts all characters in a string to lowercase. UpperCasePipe converts all characters to uppercase. Angular also provides TitleCasePipe which capitalizes the first letter of each word. These are simple transformation pipes commonly used for formatting display text consistently.
<p>{{ 'Hello World' | lowercase }}</p>    <!-- hello world -->
<p>{{ 'hello world' | uppercase }}</p>    <!-- HELLO WORLD -->
<p>{{ 'hello world' | titlecase }}</p>    <!-- Hello World -->
These pipes are pure by default so they only recalculate when the input string reference changes. They are the simplest built-in pipes and useful for consistent text formatting across your UI.

Why it matters: Tests understanding of text transformation. Shows you know simple string case handling.

Real applications: Converting user input to lowercase, displaying headers in title case, normalizing search queries, consistent button labels.

Common mistakes: Developers use JavaScript .toUpperCase() getting XSS vulnerabilities. They manually create title case logic. They don't know TitleCasePipe exists.

Pure pipes (default) are called only when Angular detects a change in the input's primitive value or object reference. Impure pipes are called on every change detection cycle, which can be dozens of times per second. This means impure pipes have a huge performance impact if the transform function is expensive. Always prefer pure pipes and use immutable data patterns to trigger recalculations.
// Pure pipe: runs only when input reference changes
@Pipe({ name: 'filterPure', pure: true })

// Impure pipe: runs on EVERY change detection cycle
@Pipe({ name: 'filterImpure', pure: false })

// To trigger pure pipe on array changes, create a new reference:
this.items = [...this.items, newItem]; // creates new array reference
To trigger a pure pipe on array mutations, create a new reference using the spread operator. If you must use an impure pipe, keep the transform logic very lightweight and fast.

Why it matters: Tests understanding of immutability and performance tradeoffs. Shows you know optimization best practices.

Real applications: Filter lists with pure pipes, sort arrays efficiently, handle frequently-changing data carefully, optimize large lists.

Common mistakes: Developers use impure pipes everywhere harming performance. They mutate arrays breaking pure pipe detection. They don't understand immutability benefits.

JsonPipe converts a JavaScript object or value to a JSON-formatted string using JSON.stringify(). It is primarily used for debugging during development to inspect object shapes or form values in the template. It displays the full nested structure of objects and arrays in a readable format. While not suitable for production UI, it is very handy for verifying data binding.
<!-- Debug object structure -->
<pre>{{ user | json }}</pre>
<!-- Output: { "name": "John", "age": 30 } -->

<!-- Debug form values -->
<pre>{{ myForm.value | json }}</pre>
<!-- Output: { "email": "test@mail.com", "password": "123" } -->
JsonPipe is an impure pipe because it needs to detect changes within objects. Use it inside <pre> tags for proper formatting in the browser.

Why it matters: Tests understanding of debugging tools. Shows you know development-time utilities.

Real applications: Debugging component state during development, inspecting API responses, verifying data binding, development console output.

Common mistakes: Developers use JsonPipe in production UI. They don't know it's impure hurting performance. They forget proper <pre> formatting for readability.