Building a custom pipes with Angular 2

Today i will talk about pipes in angular 2. Angular pipes is a great easy feature which takes in data as input and transforms it to a desired output.

Examples:

{{product.name | lowercase}}

{{product.price| currency: 'USD':true:'1.2-2'}}

As illustrated above, pipe is applied to a bounded value in a template by add a pipe symbol | then the pipe method, for example lowercase.

Angular provide a set of useful built in pipes like: date, number, decimal, percent, currency, json, slice and etc. and some of this pipes take parameters like in the currency example above.

Angular pipes is a concrete concept from angular 1 which used also in angular 2.

Now i will illustrate how to build a custom pipe in angular 2 by example.

I assumed that you familiar with Typescript and basic Angular 2 concepts like components, decorators and etc.

For example i want to build a custom pipe to allow us filter a specific bounded list of type product, The scenario will be as shown below:

We have a component to show a list of products, so we will create a folder inside app directory to contains all the feature related things.

app > products:

product.ts:

/* Defines the product entity */
export interface IProduct {
productId: number;
productName: string;
productCode: string;
releaseDate: string;
price: number;
description: string;
starRating: number;
imageUrl: string;
}

product-list.component.ts:

import { Component}  from 'angular2/core';
import { IProduct } from './product';

@Component({
templateUrl: 'app/products/product-list.component.html',
styleUrls: ['app/products/product-list.component.css']
})
export class ProductListComponent{
pageTitle: string = 'Product List';
imageWidth: number = 50;
imageMargin: number = 2;
showImage: boolean = false;
listFilter: string = '';
errorMessage: string;
products: IProduct[];

....
}

product-list.component.html:

<div class='panel panel-primary'>
<div class='panel-heading'>
{{pageTitle}}
</div>

<!-- Filter the Products -->
<div class='panel-body'>
<div class='row'>
<div class='col-md-2'>Filter by:</div>
<div class='col-md-4'>
<input type='text' [(ngModel)]='listFilter' />
</div>
</div>
<div class='row' *ngIf='listFilter'>
<div class='col-md-6'>
<h3>Filtered by: {{listFilter}} </h3>
</div>
</div>

<div class='has-error' *ngIf='errorMessage'>{{errorMessage}}</div>

<div class='table-responsive'>
<table class='table' *ngIf='products && products.length'>
<thead>
<tr>
<th>Code</th>
<th>Available</th>
<th>Price</th>
</tr>
</thead>
<tbody>
<tr *ngFor='#product of products>
<td>{{ product.productCode | lowercase }}</td>
<td>{{ product.releaseDate }}</td>
<td>{{ product.price | currency:'USD':true:'1.2-2' }}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>

Ok, now we have a component with template and some custom types like Product, We want to implement a custom filter which we can apply to the bounded value here: <tr *ngFor='#product of products>which allow us to filter the list of products by value provided to the input box here: <input type='text' [(ngModel)]='listFilter' />.

The idea of custom pipe is simple, what only we need to do is creating a class which implement an interface: PipeTransform, this interface contains only one method called transform takes a value and return another transformed value, that’s all. It also can take an arguments.

Inside app > products > we will create a new file > product-filter.pipe.ts:

import {  PipeTransform, Pipe } from 'angular2/core';
import { IProduct } from './product';
@Pipe({
name: 'productFilter'
})
export class ProductFilterPipe implements PipeTransform {
    transform(value: IProduct[], args: string[]): IProduct[] {
let filter: string = args[0] ? args[0].toLocaleLowerCase() : null;
return filter ? value.filter((product: IProduct) =&gt;
product.productName.toLocaleLowerCase().indexOf(filter) !== -1) : value;
}
}

Code above is too easy but i can put a simple notes:
1- first we imported PipeTransform, Pipe and IProduct which we will use with the pipe.
2- Second we implemented PipeTransform and start to write a code inside transform() method to transform product[] to filtered product[].
3- The logic inside transform() method is easy. First we try to get the first arg which should be our filter keyword then we use it to filter a product[] with ECMASCRIPT’s 6 syntax => which is look like lambda expression in .NET, Java 8 or any functional programming.

Then we can use the custom pipe with only two steps:

1- import it and put it in the component pipes array:

import { ProductFilterPipe } from './product-filter.pipe';
@Component({
templateUrl: 'app/products/product-list.component.html',
styleUrls: ['app/products/product-list.component.css'],
pipes: [ProductFilterPipe]
})
export class ProductListComponent{
.....
}

2- apply it on the bounded value in the component template:

<tr *ngFor='#product of products | productFilter:listFilter'>
....
</tr>

That’s all.

references:
1- Pluralsight course: Angular 2 Getting started by Deborah Kurata
2- https://github.com/DeborahK/Angular2-GettingStarted