Pipes
Pipes transform values in templates. AngularDart provides built-in pipes and allows you to create custom pipes.
Built-in Pipes
DatePipe
Format dates:
<p>{{ birthday | date }}</p>
<p>{{ birthday | date:'fullDate' }}</p>
<p>{{ birthday | date:'yMMMd' }}</p>
<p>{{ birthday | date:'HH:mm' }}</p>
CurrencyPipe
Format currency values:
<p>{{ price | currency:'USD' }}</p>
<p>{{ price | currency:'EUR' }}</p>
<p>{{ price | currency:'EUR':true }}</p>
NumberPipe
Format numbers:
<p>{{ bigNumber | number }}</p>
<p>{{ pi | number:'1.2-2' }}</p>
<p>{{ percent | percent }}</p>
UpperCasePipe / LowerCasePipe
Transform text case:
<p>{{ name | uppercase }}</p>
<p>{{ title | lowercase }}</p>
JsonPipe
Display objects as JSON (useful for debugging):
<pre>{{ user | json }}</pre>
SlicePipe
Extract a portion of a list or string:
<p>{{ 'Hello World' | slice:0:5 }}</p>
<ul>
<li *ngFor="let item of items | slice:0:5">{{ item }}</li>
</ul>
AsyncPipe
Unwrap values from streams or futures:
<p>{{ data$ | async }}</p>
<div *ngIf="users$ | async as users">
<ul>
<li *ngFor="let user of users">{{ user.name }}</li>
</ul>
</div>
Chaining Pipes
Combine multiple pipes:
<p>{{ birthday | date:'fullDate' | uppercase }}</p>
<p>{{ price | currency:'EUR' | uppercase }}</p>
Pipes with Parameters
Pass parameters to pipes:
<p>{{ value | number:'1.2-2' }}</p>
<p>{{ date | date:'yMMMd' }}</p>
Creating Custom Pipes
Create custom pipes with the @Pipe annotation:
import 'package:angulardart/angular.dart';
@Pipe('exponentialStrength')
class ExponentialStrengthPipe implements PipeTransform {
@override
num transform(num value, num exponent) {
return value * exponent;
}
}
Usage:
<p>{{ 2 | exponentialStrength:10 }}</p>
Flying Heroes Pipe
Filter a list with a custom pipe:
@Pipe('flyingHeroes')
class FlyingHeroesPipe implements PipeTransform {
@override
List<Hero> transform(List<Hero> heroes) {
return heroes.where((hero) => hero.canFly).toList();
}
}
Usage:
<div *ngFor="let hero of heroes | flyingHeroes">
{{ hero.name }} can fly!
</div>
Custom Date Format Pipe
@Pipe('customDate')
class CustomDatePipe implements PipeTransform {
@override
String transform(DateTime date) {
final now = DateTime.now();
final diff = now.difference(date);
if (diff.inMinutes < 1) return 'just now';
if (diff.inHours < 1) return '${diff.inMinutes} minutes ago';
if (diff.inDays < 1) return '${diff.inHours} hours ago';
if (diff.inDays < 7) return '${diff.inDays} days ago';
return '${date.day}/${date.month}/${date.year}';
}
}
Usage:
<p>Posted {{ post.date | customDate }}</p>
Search Filter Pipe
@Pipe('searchFilter')
class SearchFilterPipe implements PipeTransform {
@override
List<T> transform<T>(List<T> items, String query) {
if (query.isEmpty) return items;
return items.where((item) {
return item.toString().toLowerCase().contains(query.toLowerCase());
}).toList();
}
}
Usage:
<input [(ngModel)]="searchQuery" placeholder="Search...">
<ul>
<li *ngFor="let item of items | searchFilter:searchQuery">
{{ item }}
</li>
</ul>
Impure Pipes
By default, pipes are pure (only re-evaluate when input reference changes). Use impure pipes for pipes that need to re-evaluate on every change detection:
@Pipe('fetch', pure: false)
class FetchPipe implements PipeTransform {
@override
dynamic transform(Future<dynamic> future) {
// Return cached value or trigger load
}
}
Warning: Impure pipes can impact performance. Use them sparingly.
Pipe Best Practices
- Keep pipes focused on a single transformation
- Use pure pipes when possible for better performance
- Name pipes clearly (e.g.,
shorten,truncate,filter) - Consider caching expensive transformations
- Use pipes for display logic, not business logic
When to Use Pipes vs Components
Use pipes when:
- Transforming a single value for display
- The transformation is reusable across templates
- The logic is simple and stateless
Use components when:
- The transformation requires complex logic
- You need to maintain state
- The transformation involves DOM manipulation