Angular tutorial : How to Create Custom Pipe in Angular

Pipes in Angular are a great way to transform and format data right from your templates. Out of the box you get pipes for dates, currency, percentage and character cases, but you can also easily define custom pipes of your own.This is where the concept of creating a Custom Pipe in Angular comes into play, allowing us to nicely extend our applications.

What are pipes in Angular?

Angular provides some helpful filters known as Pipes which makes it very easy to format or transform the data value according to our needs.
Pipes are used with a Pipe (|) character, it takes an input and returns a desired formatted output. Simple Right?

Angular has a few built-in Pipes that ship with the framework’s CommonModule, allowing us to make use of them in any module we’re writing.

Here are a few usual suspects we could encounter with Angular’s built-in Pipes:

  • DatePipe (for parsing Date objects)
  • UpperCasePipe (for uppercase-ing Strings)
  • LowerCasePipe (for lowercase-ing Strings)
  • CurrencyPipe (for formatting currencies)
  • AsyncPipe (for unwrapping asynchronous values, such as Observables!)

In simple terms, pipes allow us to write display value transformation right inside the template. Angular comes with stock or built in pipes to transform your values to what you want the user to see. For instance, the Date Pipe, allows you to change the date format and other aspects related to the date.

That’s the essence of a Pipe!

So, how do we use a Pipe? Let’s assume some simple component HTML with a binding of a Date stamp:

<div>
  <!-- Renders: 21/10/2019 -->
  <p></p>
</div>

This could render out as above with the formatted Date. So that’s a valid use case for Pipes! We don’t really want to fetch data and then loop through it all and convert each date from a Date object to a String, as we’d lose native Date object functionality and be duplicating values. It’s super convenient to use a Pipe and let it parse out for us!

Now you’re ready to start venturing into Custom Pipes! This will allow us to use a function to create our own input and output based on what you’re supplying. Let’s dive in!

Using Custom Pipes

Let’s assume an image was just uploaded via a drag and drop zone - and we’re getting some of the information from it. A simplified file object we’ll work with:


export class FileComponent {
  file = { name: 'logo.svg', size: 2120109, type: 'image/svg' };
}


Properties name and type aren’t what we’re really interested in to learn about Pipes - however size is the one we’d like. Let’s put a quick example together for how we’ll define the usage of our pipe (which will convert numbers into filesizes):


<div>
  <p></p>
  <p></p>
</div>

Creating a Custom Pipe

To create a Pipe definition, we need to first create a class (which would live in its own file). We’ll call this our FileSizePipe, as we are essentially transforming a numeric value into a string value that’s more human readable:

export class FileSizePipe {}


Now we’ve got this setup, we need to name our Pipe. In the above HTML, we did this:


<p></p>

So, we need to name the pipe “filesize”.

import { Pipe } from '@angular/core';

@Pipe({ name: 'filesize' })
export class FileSizePipe {}

All we need to do is supply a name property that corresponds to our template code name as well (as you’d imagine).

Don’t forget to register the Pipe in your @NgModule as well, under declarations:

// ...
import { FileSizePipe } from './filesize.pipe';

@NgModule({
  declarations: [
    //...
    FileSizePipe,
  ],
})
export class AppModule {}

NOTE : Pipes tend to act as more “utility” classes, so it’s likely you’ll want to register a Pipe inside a shared module. If you want to use your custom Pipe elsewhere, simply use exports: [YourPipe] on the @NgModule.

Pipe and PipeTransform

Once we’ve got our class setup, registered, and the @Pipe decorator added - the next step is implementing the PipeTransform interface:

import { Pipe, PipeTransform } from '@angular/core';

@Pipe({ name: 'filesize' })
export class FileSizePipe implements PipeTransform {
  transform() {}
}

This creates a required contract that our FileSizePipe must adhere to the following structure:

export interface PipeTransform {
  transform(value: any, ...args: any[]): any;
}

Which is why we added the transform() {} method to our class above.

Pipe Transform Value

As we’re using our Pipe via interpolation, this is the magic on how we’re given arguments in a Pipe.

The file.size variable is passed straight through to our transform method, as the first argument.

We can call this our size and type it appropriately:

//...
export class FileSizePipe implements PipeTransform {
  transform(size: number) {}
}

From here, we can implement the logic to convert the numeric value into a more readable format of megabytes.

//...
export class FileSizePipe implements PipeTransform {
  transform(size: number): string {
    return (size / (1024 * 1024)).toFixed(2) + 'MB';
  }
}


We’re returning a type string as we’re appending 'MB' on the end. This will then give us:

<!-- 2.02MB -->

We can now demonstrate how to add your own custom arguments to custom Pipes.

Pipes with Arguments

So let’s assume that, for our use case, we want to allow us to specify the extension slightly differently than advertised.

Before we hit up the template, let’s just add the capability for an extension:

//...
export class FileSizePipe implements PipeTransform {
  transform(size: number, extension: string = 'MB'): string {
    return (size / (1024 * 1024)).toFixed(2) + extension;
  }
}

I’ve used a default parameter value instead of appending the 'MB' to the end of the string. This allows us to use the default ‘MB’, or override it when we use it. Which takes us to completing our next objective of passing an argument into our Pipe:

<!-- 2.02megabyte -->


And that’s all you need to supply an argument to your custom Pipe. Multiple arguments are simply separated by :, for example:

Don’t forget you can chain these pipes alongside others, like you would with dates and so forth.

Here’s the final assembled code:


import { Pipe, PipeTransform } from '@angular/core';

@Pipe({ name: 'filesize' })
export class FileSizePipe implements PipeTransform {
  transform(size: number, extension: string = 'MB') {
    return (size / (1024 * 1024)).toFixed(2) + extension;
  }
}

Want a challenge? Extend this custom Pipe that allows you to represent the Pipe in Gigabyte, Megabyte, and any other formats you might find useful. It’s always a good exercise to learn from a starting point!

Learn More

#angular #developer

Angular tutorial : How to Create Custom Pipe in Angular
1 Likes11.30 GEEK