Custom Pipes in Angular 2

I am working on a project that is using an ASP.NET Core web API to return JSON that is then used by Angular 2. The dates that needed to be formatted before being shown to the user which lead me to pipes.

Pipes

In Angular 2 pipes are away to apply some transformation on a field before its value is displayed to the user. Some common pipes are provided out of the box for things like numbers, dates and percentages.

For the following example created  is a property for the date a contact was added. To have created just display the month, date and year the date pipe will be used with the short date format.

{{contact.created | date: 'shortDate'}}

The above is standard Angular 2 binding  with an added pipe “|” followed by the name of the pipe which in this case is date. The built-in date pipe can take arguments for how to the date should be formatted. If the created date was today than the resulting output of the above binding would be 4/10/2016. For a full list of built-in formats see the Angular docs.

The Problem

I added the date pipe to the fields that needed formatting and ran the app. Instead of the formatted date I was expecting I got a partially rendered page. A quick peek in Chrome’s dev tools showed the following exception.

EXCEPTION: Invalid argument ‘2016-04-10T08:00:00’ for pipe ‘DatePipe’ in [{{contact.created | date: ‘shortDate’}}

Turns out that the date pipe only works if the value it is processing is a number or a date. I found this out by looking at the code for the date pipe which can be found here. My created property came from JSON which doesn’t have a way to denote something as a date. This means the created property is actually a string instead of a date..

Solution 1 – Convert to a date

One way to fix this issue is to use the string representation of the date to create a new date and assign it over the top of the existing property. For example:

contact.created = new Date(contact.created);

After the above is applied to all the dates that need formatted Angular’s date pipe can be used with no problems.

Solution 2 – Custom pipe

I decided to try writing a custom pipe that would take a string that should be a date and format it if it is actually date using Angular’s date pipe.  The following is the resulting pipe.

import {Pipe, PipeTransform} from 'angular2/core';
import {DatePipe} from 'angular2/common';

@Pipe({ name: 'dateString' })
export class DateString implements PipeTransform {
    transform(value: string, args: any[]): string {
        var parsedDate = Date.parse(value);
        if (isNaN(parsedDate)) {
            return "";
        }
        else {
            return new DatePipe().transform(new Date(parsedDate), args);
        }
    }
}

First Pipe and PipeTransform are imported. The class must be decorated with @Pipe which is also used to give the pipe its name. The class must also implement PipeTransform which defines a transform function.

The transform function is where all the work happens. It takes a value and formatting arguments and return the value that should be displayed. In my case the value is parsed to a date which returns the number of milliseconds since January 1, 1970 00:00:00 UTC or not a number if parsing fails for some reason. For the not a number result an empty string will be return and displayed to the user.

In the case the date is value then a new instance of Angular’s date pipe is created it handles formatting using the new date value which is then return and displayed for the user. In order to use Angular’s date pipe inside my custom pipe it needed to be imported as well.

Custom Pipe Usage

To use a custom pipe it must be imported by the view model class of the view that needs formatted.

import { DateString } from './dateString.pipe';

Then it must be added to the component decorator.

@Component({
    selector: 'viewContacts',
    templateUrl: 'viewContacts.component.html',
    pipes: [DateString]
})

The view will now be able to use the pipe. The syntax is the same as built-in pipes just with the name provided in the pipe decorator which is dateString in this example.

{{contact.created | dateString: 'shortDate'}}

Suggestions

The above are two of the solutions I came up with when I had problems with Angular’s built in date pipe. They are by no means the only options. If you have a suggestion on a better way to handle dates coming from JSON please leave a comment.

Also note that there is an issue logged on the Angular repo to support strings in the built in date pipe which can be found here.

Custom Pipes in Angular 2 Read More »