Thursday, December 10, 2020

Pure and Impure Pipes in Angular

When you create a custom pipe in Angular there is one more attribute of @Pipe decorator which you can assign a value as true or false, that attribute is pure. In this tutorial we’ll see what are pure and impure pipes in Angular and what are the differences between pure and impure pipes.

@Pipe({
  name: 'myCustomPipe', 
  pure: false/true
})
export class MyCustomPipe {

}

By default, pipes are defined as pure so you don't explicitly need to assign value of pure as true.


Pure pipes in Angular

Angular pipes use data binding, if the data is a primitive input value like String or Number or an object reference such as Date or Array, Angular executes the pipe whenever it detects a change for the input value or reference.

Pure pipes in Angular (which is also default) are executed only when Angular detects a pure change to the input value. A pure change is either a change to a primitive input value (such as String, Number, Boolean, or Symbol), or a changed object reference (such as Date, Array, Function, or Object).

A pure pipe must use a pure function. A pure function always return the same output for the same input. For example following function to add number is a pure function calling it multiple times with argument 2 and 3 gives the same result 5.

addPure(a, b) {
  return a + b;
};

With a pure pipe, Angular ignores changes within objects. If you add an element to an existing array that won’t be considered by a pure pipe, because checking a primitive value or object reference is much faster than performing a deep check for differences within objects.

Impure pipes in Angular

If you want pipe to be executed after a change within an object, such as a change to an element of an array, you need to define your pipe as impure to detect impure changes.

An impure pipe is called for every change detection cycle which could slow down your app drastically so be very careful with implementing an impure pipe in Angular.

Pure and impure pipe Angular example

In the example we’ll create an Angular app to display user data. We’ll create a custom pipe to filter the data on firstName.

Pure pipe in Angular

Custom pipe class (filter.pipe.ts)

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

@Pipe({
  name:'filter'
})
export class FilterPipe implements PipeTransform{
  transform(value: any, name: string) {
    if(name === ''){
      return value;
    }
    return value.filter((user) => user.firstName.startsWith(name));
  }
}

Component Class (app.component.ts)

In the component class there is an array users storing user details. There is also a property nameString used for two way binding with the input value in the template for the search.

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

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html', 
})
export class AppComponent{
  nameString = '';
  users = [{
      firstName: 'John',
      lastName: 'Doe',
      dept: 'Finance',
      salary: 5000,
      doj: new Date('2015-12-11')
    }, 
    {
      firstName: 'Amy',
      lastName: 'Watson',
      dept: 'HR',
      salary: 8000,
      doj: new Date('2013-07-23')
    }, 
    {
      firstName: 'Shrishti',
      lastName: 'Sharma',
      dept: 'IT',
      salary: 10000,
      doj: new Date('2019-10-20')
    }
  ]
}

Template (app.component.html)

<div class="container">
  <h1>User Details</h1>
  <span>Search </span><input type="text" [(ngModel)]="nameString">
  <br/><br/>
  <table class="table table-sm table-striped m-t-4">
    <thead class="thead-dark">
      <tr>
      <th>First Name</th>
      <th>Last Name</th>
      <th>Department</th>
      <th>Salary</th>
      <th>Joining Date</th>
    </tr>
  </thead>
  <tbody>
    <tr *ngFor="let user of users | filter:nameString">
      <td>{{user.firstName}}</td>
      <td>{{user.lastName}}</td>
      <td>{{user.dept}}</td>
      <td>{{user.salary}}</td>
      <td>{{user.doj | date:'dd/MM/yyyy'}}</td>
    </tr>
  </tbody>
  </table>
</div>

In the template there is an input element with a two way binding done for the “nameString” property in the component.

As you can see filter pipe is used here with in the ngFor directive. Since it is bound with the users array so that is passed as the value. Parameter passed with the pipe here is nameString which is the value of the search string.

Here is a screen shot of how you can use this filter pipe.

pure vs impure pipe Angular

Adding pipe declaration to the AppModule

If you have created the Pipe class yourself then you do need to add it to the AppModule class youself too. Add the class in the declarations array.

@NgModule({
  declarations: [
    AppComponent,
    FilterPipe
  ],
  ...
  ...
})
export class AppModule { }

Now to show what is the difference between pure pipe and impure pipe in Angular let’s add two methods in the component class one to add a new user to the already existing array of users and another to change the reference of the array.

addUser(){
  this.users.push({
    firstName: 'Alia',
    lastName: 'Bajaj',
    dept: 'Finance',
    salary: 6000,
    doj: new Date('2016-09-16')
  })
}
reset(){
  this.users = this.users.slice()
}

Two buttons are also added to the template to call these methods.

<button type="button" class="btn btn-success m-3" (click)="addUser()">Add User</button>
<button type="button" class="btn btn-success" (click)="reset()">Reset</button>
Angular pipe

With these changes you can see that when the filtering is done on ‘A’ and you click on Add User button that change won’t be reflected in the filtered result because pure pipe ignores changes within objects. If you click on reset now which changes the array reference itself then the change is reflected.

Another way to make the changes in the array reflected when filtering is to make the pipe impure. You can test that by making the following change in the FilterPipe.

@Pipe({
  name:'filter',
  pure: false
})
export class FilterPipe implements PipeTransform{
  ...
  ...
}

With this change when you click on Add User button that change will be reflected in the filtered result as FilterPipe is an impure pipe now and it will be executed after a change within an object.

That's all for this topic Pure and Impure Pipes in Angular. If you have any doubt or any suggestions to make please drop a comment. Thanks!

>>>Return to Angular Tutorial Page


Related Topics

  1. Angular Pipes With Examples
  2. Using Angular Pipes in Component or Service Classes
  3. Custom Async Validator in Angular Template-Driven Form
  4. What is Client Side Routing in Angular
  5. Angular Disable Button Example

You may also like-

  1. Angular - Call One Service From Another
  2. Custom Async Validator in Angular Reactive Form
  3. Angular Custom Property Binding Using @Input Decorator
  4. Nested Route (Child Route) in Angular
  5. Java String Interview Questions And Answers
  6. Java BufferedWriter Class With Examples
  7. StringJoiner Class in Java With Examples
  8. Dependency Injection Using factory-method in Spring

No comments:

Post a Comment