In the tutorial, we show how to create an Angular Custom Pipe with Angular Pure Pipe, and Angular Impure Pipe.
Related posts:
– Angular Built-in DatePipe Example | Pre-defined Format + Timezone + Locale + Custom Format
– Angular 6 – KeyValue Pipe – *ngFor Loop through Object, Map example
– How to Integrate Bootstrap with Angular (Angular 6)
– Angular 6 Component – How to create & integrate New Angular 6 Component
– Angular NgFor Repeater Directive – Loop over a Collection (Angular 6)
Related pages:
Custom Pipe
We can write our own custom pipes.
Example: create a pipe that calculates a logarithm of a number with the base value.
->
1 2 3 4 5 6 7 8 |
import { Pipe, PipeTransform } from '@angular/core'; @Pipe({name: 'logbase'}) export class Logarithm implements PipeTransform { transform(value: number, base: number): string { return (Math.log(value) / Math.log(base)).toPrecision(2); } } |
– The @Pipe
decorator allows you to define the pipe name that you’ll use within template expressions.
– PipeTransform
interface’s transform
method that accepts an input value followed by optional parameters and returns the transformed value.
->
1 2 3 |
export interface PipeTransform { transform(value: any, ...args: any[]): any; } |
We must include custom pipe in the declarations
array of the AppModule
->
1 2 3 4 5 6 7 8 9 10 |
@NgModule({ declarations: [ ... Logarithm, ... ], ... }) export class AppModule { } |
Now we create a baselog
component to use above custom pipe logbase
->
– baselog.component.ts
->
1 2 3 4 5 6 7 8 9 10 |
import { Component, OnInit } from '@angular/core'; @Component({ selector: 'app-baselog', templateUrl: './baselog.component.html', }) export class BaselogComponent { number = 8; base = 2; } |
– baselog.component.html
->
1 2 3 4 5 6 |
<h3>Logarithm Calculator</h3> <div>Number: <input [(ngModel)]="number"/></div> <div>LogBase: <input [(ngModel)]="base"/></div> <p> Value: {{number | logbase: base}} </p> |
-> result:
Pure Pipe and Impure Pipe
Problem
Follow the above custom pipe, we create a even
pipe to filter even numbers in a given number array.
->
1 2 3 4 5 6 7 8 |
import { Pipe, PipeTransform } from '@angular/core'; @Pipe({ name: 'even' }) export class Evenpipe implements PipeTransform { transform(nums: number[]) { return nums.filter(num => num%2==0); } } |
Now we create an evenums
component that uses even
:
– evennums.component.ts
->
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
import { Component, OnInit } from '@angular/core'; @Component({ selector: 'app-evennums', templateUrl: './evennums.component.html' }) export class EvennumsComponent{ nums =[1, 2, 3, 4]; addNumber(number: number) { this.nums.push(number); //this.nums = this.nums.concat(number); } } |
– evennums.component.html
->
1 2 3 4 5 6 7 8 9 10 11 12 |
<h3>Array Numbers</h3> <input type="text" #box (keyup.enter)="addNumber(box.value); box.value=''" placeholder="number"> <h6>All Numbers</h6> <div *ngFor="let num of nums"> {{num}} </div> <h6>Even Numbers</h6> <div *ngFor="let num of (nums | even)"> {{num}} </div> |
Results:
– Inital state -> it works well:
– Add an even
-> even
pipe does NOT work well.
-> Why?
We can find all solutions in below sessions Pure
& Impure
pipes. Let’s go ->
Pure Pipe
Angular has 2 kinds of pipe: pure
& impure
.
In Angular, Pure
is default pipe.
– Angular executes a pure pipe only when it detects a pure change to the input value.
– A pure
change is either a change to a primitive input value (String
, Number
, Boolean
, Symbol
) or a changed object reference (Date
, Array
, Function
, Object
).
That is the reason, we got the above problems, even
pipe does NOT work.
We use push
method to add new number to exist array:
this.nums.push(number);
-> So the reference of array did NOT change. Then pure even
pipe did NOT work.
How to fix it?
Solution -> change the array referene when adding a new item, see below code:
this.nums = this.nums.concat(number);
-> Test:
It works well now! -> Congratulation!!!
Have other solution? -> We can use impure pipe
with below session.
Impure Pipe
An impure
pipe is called often because Angular executes an impure
pipe during every component change detection cycle.
-> Must more take care about performance for user experience when using impure
pipe because it is expensive, long-running.
How to implement an Angular impure
pipe?
-> The same ways that we had developed a custom pipe (pure pipe). The only difference point is the pure: false
flag.
Now we implements an evenImpurePipe
pipe ->
1 2 3 4 5 6 7 8 9 |
import { Pipe, PipeTransform } from '@angular/core'; import { Evenpipe } from './evenpipe'; @Pipe({ name: 'evenImpurePipe', pure: false }) export class Evenimpurepipe extends Evenpipe { } |
Don’t forget to include evenImpurePipe
pipe in the declarations
array of the AppModule
->
1 2 3 4 5 6 7 8 9 10 |
@NgModule({ declarations: [ ... Evenpipe, Evenimpurepipe, ], ... }) export class AppModule { } |
– Change the style of evennums
component as below:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<h3>Array Numbers</h3> <input type="text" #box (keyup.enter)="addNumber(box.value); box.value=''" placeholder="number"> <h6>All Numbers</h6> <div *ngFor="let num of nums"> {{num}} </div> <h6>Even Numbers</h6> <!-- <div *ngFor="let num of (nums | even)"> --> <div *ngFor="let num of (nums | evenImpurePipe)"> {{num}} </div> |
– Implement addNumber
with push
method:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
import { Component, OnInit } from '@angular/core'; @Component({ selector: 'app-evennums', templateUrl: './evennums.component.html' }) export class EvennumsComponent{ nums =[1, 2, 3, 4]; addNumber(number: number) { this.nums.push(number); //this.nums = this.nums.concat(number); } } |
Results -> It works well:
SourceCode
Project Structure ->
Results ->
SourceCode ->