<!-- 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.
<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.
<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.
@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.
@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.
// 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.
<!-- 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.
@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.
<!-- 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.
<!-- 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.
<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.
<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%.
<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 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.
<!-- 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.