a blog for those who code

Tuesday 2 April 2019

Why Pipes are Useful in Angular and How to Create Custom Pipes


Pipes are useful in Angular because it is used to transform the data in a template. Let's take an example of date, a date in raw string looks like `Tue Apr 02 2019 13:37:27 GMT+0530 (India Standard Time)` and what if you don't want to show a raw string to the user but only a simple format like April 02, 2019. You might be thinking that this can easily be done in the typescript file, but instead if you only want it for displaying purpose why not transform it on the template using pipes.

So the main concept of using Pipes is whenever we want to perform some logic to transform the data inside our templates we use pipes. We use a pipe with the | syntax in the template. So like our example if we want to transform the date we will write :

{{ myDate | date:'longDate' }}

The above code will take the date and transform it to long date string.

Understanding Reactive and Template-driven Forms in Angular

Built-In Pipes

Angular provides a lot of built-in pipes and they are :

1. CurrencyPipe - It transforms a number to a currency.

{{ 1234.45 | currency:'INR'}} // ₹1,234.45
{{ 1234.45 | currency:'INR':'code'}} // INR1,234.45

2. DatePipe - It transforms date value

{{ '1554195345528' | date:'longDate' }} // April 2, 2019
{{ '1554195345528' | date:'full' }} // Tuesday, April 2, 2019 at 2:25:45 PM GMT+05:30

3. DecimalPipe - It transforms a decimal to a string. It takes a format string of the form {minIntegerDigits}.{minFractionDigits}-{masFractionDigits}

{{ 1.4587545 | number: '3.1-4'}} //001.4588

4. JsonPipe - It transforms a value into JSON-format. Let's say we have a JSON in our typescipt file

myJson = { a: 'a', b: { c: 'd' }}

{{ myJson }} // [object Object]
{{ myJson | json }} // {"a": "a", "b": {"c": "d"}}

5. LowerCasePipe, UpperCasePipe and TitleCasePipe - It transforms text to lower case, upper case and title case (capitalizes first letter) respectively.

{{ 'coDing DeFined' | lowercase }} // coding defined
{{ 'coDing DeFined' | uppercase }} // CODING DEFINED
{{ 'coDing DeFined' | titlecase }} // Coding Defined

6. PercentPipe - It transforms a number to a percentage string

{{ .256 | percent}} // 26%

7. SlicePipe - It creates a new string containing a subset of the elements

{{ 'Coding Defined ' | slice:0:5 }} // Codin

8. AsyncPipe - It transforms an Observable or Promise to the output. In simple terms it means that async pipe subscribes to an Observable and Promise and returns the value it emitted.

Lets have the below code in our typescript file

export class AppComponent implements OnInit {
 myPromise: Promise<string>;

 ngOnInit() {
  this.myPromise = this.getData();
 }

 getData() {
  return new Promise<string>((resolve,reject) => {
    setTimeout(() => resolve("Got Data"), 2000);
  });
 }
}

And in the template file we will write, thus after 2 seconds we will able to see our data

{{ myPromise | async }}

How to Solve: InvalidPipeArgument for pipe 'AsyncPipe'

Sometimes you might get the error as InvalidPipeArgument for pipe 'AsyncPipe', it actually means that you are not binding the async to Observables and Promises. Thus always check if the data you are binding to AsyncPipe is Observables or Promise and not anything else.

Parameterized Pipes

So we have looked at almost all the built in pipes. One thing you might have noticed is that we used ':' (colon) after some of the pipes and those are parameters to the pipes. Thus to add a parameter to a pipe, you just have to add a colon (:) after the pipe name like currency:'INR'. The pipe can accept multiple parameters, where you have to separate the values with colons like slice:0:5.

Understanding Observable - A key Concept in Angular

Chaining Pipes

We can also chain pipes together as shown below, where the data when received is changed to uppercase

{{ myPromise | async | uppercase }}

How to Create Custom Pipes

Let's create a simple TimeAgo Pipe which tells 'few seconds ago', 'few minutes ago' etc. We will name our pipe as simpletimeago. So when we use it in the template it will look like

{{ date | simpletimeago }}

Thus we will create a new file called simpletimeago.pipe.ts, which should have one special method to be used as a pipe and that is transform. To create a Pipe, we must implement PipeTransform interface and have trasnform method in our class. The transform methos will also get a value which will get transformed, in our case the value is of type Date. It also should have a @Pipe decorator, which marks a class as pipe and supplies configuration metadata like name an pure/unpure.

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

@Pipe({ name: 'simpletimeago' })
export class SimpleTimeAgoPipe implements PipeTransform {
  transform(value: Date): string {
    let timeNow = new Date();
    let seconds = Math.floor((timeNow.getTime() - value.getTime()) / 1000);
    let minutes = Math.floor(seconds / 60);
    if(seconds <= 30) {
      return 'a few seconds ago';
    } else if(seconds <= 75) {
      return 'a minute ago';
    } else {
      return minutes + ' minutes ago';
    }
  }
}

The code just checks if the difference between the seconds is less than 30 it will display 'a few seconds ago', if the seconds is less than 75 it will display 'a minute ago', otherwise it will display total minutes ago.

Then I have to add my pipe to the Declarations in the app module as shown below :

import { SimpleTimeAgoPipe } from './simpletimeago.pipe';

@NgModule({
  declarations: [ SimpleTimeAgoPipe ],
})

My app.component looks like below where I am creating a new date for displaying different strings

import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})

export class AppComponent implements OnInit {
 secondsDate: Date;
 minutesDate: Date;
 moreMinutesDate: Date;

 ngOnInit() {
  this.secondsDate = new Date( Date.now() );
  this.minutesDate = new Date( Date.now() - 1000 * 60 );
  this.moreMinutesDate = new Date( Date.now() - 1000 * 600 );
 }
}

And in the template I will be showing:

<br>
{{ secondsDate | simpletimeago }}
<br>
{{ minutesDate | simpletimeago }}
<br>
{{ moreMinutesDate | simpletimeago }}
<br>

Which will display as :

a few seconds ago
a minute ago
10 minutes ago

Thus we have successfully created a Pipe. Hope you understand how Pipes work in Angular.

Career Category (English)728x90

No comments:

Post a Comment