Master Angular directives and pipes. Learn to use built-in directives, create custom directives and pipes, and transform data efficiently in templates.
Master Angular directives and pipes. Learn to use built-in directives, create custom directives and pipes, and transform data efficiently in templates.
Directives are instructions in the DOM that tell Angular how to transform or manipulate elements.
Angular provides three types of directives:
Component Directives:
Directives with a template (most common)
Structural Directives:
Change the DOM layout by adding/removing elements (@if, @for)
Attribute Directives:
Change the appearance or behavior of elements (ngClass, ngStyle)
Angular 17+ introduces new control flow syntax that replaces traditional structural directives
with a more intuitive and performant approach:
Learn about @if Directive.
1@if (isLoggedIn) {
2 <div>Welcome back!</div>
3} @else if (isGuest) {
4 <div>Welcome, guest!</div>
5} @else {
6 <div>Please log in</div>
7}Learn about @for Directive.
1@for (user of users; track user.id) {
2 <div class="user-card">{{ user.name }}</div>
3} @empty {
4 <div>No users found</div>
5}Learn about @switch Directive.
1@switch (status) {
2 @case ('loading') {
3 <div>Loading...</div>
4 }
5 @case ('success') {
6 <div>Success!</div>
7 }
8 @default {
9 <div>Unknown status</div>
10 }
11}Attribute directives modify the appearance or behavior of elements without changing the DOM structure:
Learn about ngClass.
1<div [ngClass]="{
2 'active': isActive,
3 'disabled': isDisabled,
4 'highlighted': score > 80
5}">
6 Dynamic classes
7</div>Learn about ngStyle.
1<div [ngStyle]="{
2 'color': textColor,
3 'font-size.px': fontSize,
4 'background-color': bgColor
5}">
6 Dynamic styles
7</div>Custom directives allow you to encapsulate reusable DOM manipulation logic. Here's how to create
a custom attribute directive:
1import { Directive, ElementRef, HostListener, Input } from '@angular/core';
2
3@Directive({
4 selector: '[appHighlight]',
5 standalone: true
6})
7export class HighlightDirective {
8 @Input() appHighlight = 'yellow';
9 @Input() defaultColor = 'transparent';
10
11 constructor(private el: ElementRef) {}
12
13 @HostListener('mouseenter') onMouseEnter() {
14 this.highlight(this.appHighlight);
15 }
16
17 @HostListener('mouseleave') onMouseLeave() {
18 this.highlight(this.defaultColor);
19 }
20
21 private highlight(color: string) {
22 this.el.nativeElement.style.backgroundColor = color;
23 }
24}Pipes transform data in your templates without changing the underlying data. Angular provides
many built-in pipes for common transformations:
Learn about Built-in Pipes.
1<!-- Date Pipe -->
2<p>{{ today | date:'fullDate' }}</p>
3<p>{{ today | date:'short' }}</p>
4
5<!-- Currency Pipe -->
6<p>{{ price | currency:'USD':'symbol':'1.2-2' }}</p>
7
8<!-- Uppercase/Lowercase -->
9<p>{{ name | uppercase }}</p>
10<p>{{ title | lowercase }}</p>
11
12<!-- Decimal Pipe -->
13<p>{{ value | number:'1.2-3' }}</p>
14
15<!-- Percent Pipe -->
16<p>{{ ratio | percent:'1.2-2' }}</p>
17
18<!-- JSON Pipe (for debugging) -->
19<pre>{{ user | json }}</pre>
20
21<!-- Slice Pipe -->
22<p>{{ longText | slice:0:100 }}</p>
23
24<!-- Async Pipe (for Observables) -->
25<p>{{ user$ | async }}</p>Custom pipes allow you to create reusable data transformation logic. Here's how to build
a custom pipe:
Learn about Example: Truncate Pipe.
1import { Pipe, PipeTransform } from '@angular/core';
2
3@Pipe({
4 name: 'truncate',
5 standalone: true
6})
7export class TruncatePipe implements PipeTransform {
8 transform(value: string, limit: number = 50, trail: string = '...'): string {
9 if (!value) return '';
10 return value.length > limit
11 ? value.substring(0, limit) + trail
12 : value;
13 }
14}
15
16// Usage in template:
17// <p>{{ longText | truncate:100:'...' }}</p>Learn about Example: Filter Pipe.
1import { Pipe, PipeTransform } from '@angular/core';
2
3@Pipe({
4 name: 'filter',
5 standalone: true,
6 pure: false // Use with caution - triggers on every change
7})
8export class FilterPipe implements PipeTransform {
9 transform(items: any[], searchTerm: string, key: string): any[] {
10 if (!items || !searchTerm) return items;
11
12 return items.filter(item =>
13 item[key].toLowerCase().includes(searchTerm.toLowerCase())
14 );
15 }
16}
17
18// Usage:
19// @for (user of users | filter:searchTerm:'name'; track user.id) {
20// <div>{{ user.name }}</div>
21// }Understanding pipe performance is crucial for building efficient Angular applications:
Execute only when input value or reference changes
More performant and recommended for most use cases
Don't detect changes within objects or arrays
Execute on every change detection cycle
Can detect changes within objects and arrays
More expensive performance-wise
pure: false
Use sparingly and only when necessary
Use new control flow syntax (@if, @for) in Angular 17+ for better performance
Prefer built-in directives and pipes when available
Keep custom directives focused on a single responsibility
Use pure pipes (default) for better performance
Always provide a track function with @for for optimal rendering
Test custom directives and pipes thoroughly
Use HostListener and HostBinding for event handling in directives
Document custom pipes with clear examples and parameter descriptions
Consider memoization for expensive pipe transformations
Directives extend HTML with custom behavior - structural directives modify DOM structure, attribute directives modify element behavior
Angular 17+ introduces @if, @for, and @switch for cleaner and more performant template logic
Custom directives should use HostListener for events and HostBinding for property binding
Pipes transform data in templates without modifying the source data
Built-in pipes cover common transformations: date, currency, uppercase, lowercase, number, percent, json, slice, and async
Pure pipes (default) only execute when input value changes, providing better performance
Impure pipes execute on every change detection and should be used sparingly
Custom pipes implement PipeTransform interface with a transform() method
Always use track functions with @for loops to optimize rendering and prevent unnecessary DOM updates
Your progress is saved in this browser, on this device only.