Category Archives: Typescript

Change detection in Angular (Obviously 2.0 & greater)

Let me define first what change detection is, in simple terms any state change that needs to be propagated to UI and ice versa. Now the application state changes can happen in   following ways which apparently all are asynchronous in nature.

  • Events – Click, selection changed, keyup
  • Remote API Ajax Calls(XHR)
  • Timers – setTimeout(), setInterval()

Now for sure we know what how the application state change happens but there is still work of notifying Angular that state has changed and do the further magic. After all in the angular code we are still using Native API’s (like setTimeOut…) there are no angular specific API’s. So there is some thing called as Zone.js which does all the magic. You must have seen zone references whenever u see any error in the console window.

So what are zone and how do they work?

As one liner definition we can say that Zones are basically an execution context for asynchronous operations. Zones basically monkey patch these native methods and provide hooks for executing change detection.  As soon as we embed zone.js in our site, pretty much all methods that cause asynchronous operations are monkey-patched to run in a new zone. For example, when we call setTimeout() we actually call Zone.setTimeout().

So now we know that zones have hooks for asynchronous operation but how does it marry with angular, answer lies in to the ApplicationRef class and source code below, it simplified version of the code….

class ApplicationRef {

  changeDetectorRefs:ChangeDetectorRef[] = [];

  constructor(private zone: NgZone) {
    this.zone.onTurnDone
      .subscribe(() => this.zone.run(() => this.tick());
  }

  tick() {
    this.changeDetectorRefs
      .forEach((ref) => ref.detectChanges());
  }
}

ApplicationRef listens to NgZones onTurnDone event. Whenever this event is fired, it executes a tick() function which essentially performs change detection.

In Angular, each component has its own change detector. So in the component tree each component will have its own change detector. This allows us to control, for each component individually, how and when change detection is performed

ChnageDetection1

Let us assume that in the component tree an event has been triggered in the Child 2.1 component.  As mentioned earlier zones have hook in to these event handlers, zones execute the given handler and notify Angular when it is done, which eventually causes Angular to perform change detection. Now for angular change detection always flows from top to bottom. Change detection is also always performed from top to bottom for every single component, every single time, starting from the root component

ChnageDetection2ChnageDetection3ChnageDetection4

This is much more predictable change detection than in Angular JS where it used to digest loop or cycle.

CD (change detection) gets stable after a one pass, if one of our components causes any additional side effects after the first run during change detection, then angular will throw an exception.

Now that we have talked @ Change detectors in Angular but what are these Change detectors, well these are not one fit all generic classes which does the change detection for all components. Angular creates CD classes at runtime for each component, which are monomorphic, because they know exactly what the shape of the component’s model is.  Monomorphic are king of opposite of polymorphic which do not have any runt time overrides or sub types.

Angular also gives control of the change detection, if we wish to. We can tell angular to run CD only for the part of the component hierarchy tree. This can be achieved with 2 things

  • Immutable data structures
  • Observables

Lets consider optimization through Immutability first, consider the followin component

import { Component, OnInit } from '@angular/core';
import { UtilityService } from './../services/utility.service';
@Component({
  templateUrl: ''
})
export class GrandChildComponent implements OnInit {
  public greatGrandChildDetails: GreatGrandChildDetails;
  public currentDateTime : string;
  constructor(private utilService: UtilityService) {
    this.currentDateTime = this.utilService.currentDateTime.toISOString();
    this.greatGrandChildDetails = new GreatGrandChildDetails();
    this.greatGrandChildDetails.firstName = "Amol";
    this.greatGrandChildDetails.lastName = "Gote";
   }

  ngOnInit() {
  }

  changeGrandChildData(){
    this.greatGrandChildDetails.firstName = "John";
    this.greatGrandChildDetails.lastName = "Doe";
  }

}

export class GreatGrandChildDetails{
  firstName: string;
  lastName: string;
}

GrandChildComponent uses as a child component, which has an input property details. We’re passing data to that component with GrandChildComponent own greatGrandChildDetails property. greatGrandChildDetails is an object with two properties. In addition, there’s a method changeGreatGrandChildData(), which changes the first name and last name of greatGrandChildDetails, No magic going on here.
The important part is that changeGreatGrandChildData() mutates greatGrandChildDetails, by changing its first and last name property. Even though that property is going to be changed, the greatGrandChildDetails reference itself stays the same.
What happens when change detection is performed, assuming that some event causes changeGreatGrandChildData() to be executed? First, greatGrandChildDetails.firstName and greatGrandChildDetails.lastName gets changed, and then it’s passed to . ’s change detector. It now checks if the given details (greatGrandChildDetails) is still the same as before, and yes, it is (reference hasn’t changed), however, the first and last name property has changed, so Angular will perform change detection for that object nonetheless. Because objects are mutable by default in JavaScript (except for primitives), Angular has to be conservative and run change detection every single time for every component when an event happens. This is where immutable data structures come into play.

Immutable objects cannot be changed and we have to change then we have change the reference.

this.greatGrandChildDetails = Immutable.create({
              firstName: 'Amol',
              lastName: 'Gote'
            });

this.greatGrandChildDetailsNew = this.greatGrandChildDetails
                                  .set('firstName', 'John');

In the above case Immutable.create is just sample API to create Immutable, you can use any library to create immutable objects. Now when I am changing the first Name property then it is going to return a whole new reference to the object.

this.greatGrandChildDetails !=== this.greatGrandChildDetailsNew from a reference perspective both are pointing to different references. If we use immutable objects in our Angular app, all we need to do is tell Angular that a component can skip change detection, if the input has not changed, let’s look at the great-grand-child component.

Immutable-Component

We can skip entire subtrees when immutable objects are used and Angular is informed accordingly.
Immutable
ChangeDetectionStrategy.OnPush – This will inform Angular that our component only depends on its inputs and that any object that is passed to it should be considered immutable.

Now let’s talk @ Observables

Observables give us some guarantees of when a change has happened, unlike immutable objects, they don’t give us new references, instead, they fire events we can subscribe to in order to react to them.

Lets look at this example

import { Component, OnInit, ChangeDetectionStrategy, Input } from '@angular/core';
import { UtilityService } from './../services/utility.service';
@Component({
  template: '{{hitCounter}}',
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class ChildComponent implements OnInit {

  @Input() addChildItemStream:Observable;
  public hitCounter : number = 0;

  ngOnInit() {
    this.addChildItemStream.subscribe(() => {
      this.hitCounter++; 
    })
  }

}

We set the change detection strategy to OnPush, so change detection isn’t performed all the time, only when the component’s input properties change, the reference of addChildItemStream will never change, so change detection is never performed for this component’s subtree. This is a problem because the component subscribes to that stream in its ngOnInit life cycle hook and increments the counter. This is application state change and we want to have this reflected in our view. This is where ChangeDetectorRef comes to the rescue, it has an API markForCheck(), it marks the path from our component until root to be checked for the next change detection run, it simply iterates upwards and enables checks for every parent component up to the root.

import { Component, OnInit, ChangeDetectionStrategy, Input, ChangeDetectorRef } from '@angular/core';
import { UtilityService } from './../services/utility.service';
@Component({
  template: '{{hitCounter}}',
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class ChildComponent implements OnInit {

  @Input() addChildItemStream:Observable<any>;
  public hitCounter : number = 0;
  constructor(private changeDetector: ChangeDetectorRef) {

  }

  ngOnInit() {
    this.addChildItemStream.subscribe(() => {
      this.hitCounter++; // application state changed
      this.changeDetector.markForCheck();
    })
  }

}

Hierarchical Dependency Injection in Angular

DI (Dependency Injection) in Angular 2.0 is hierarchical in nature, for dependency injection to be able to create instances for you, you need to register providers for these classes (or other values) somewhere. and you can configure providers for DI at different levels

  • For the whole application when bootstrapping it. In this cases, all sub injectors (the component ones) will see this provider and share the instance associated with. When interacting, it will be the same instance
  • For a specific component and its sub components. Same as before but for à specific component. Other components won’t see this provider. If you redefine something defined above (when bootstrapping for example), this provider will be used instead. So you can override things. If a provider is registered in one of the child components a new (different) instance is provided for descendants of this component.
  • If a component requests an instance (by a constructor parameter), DI looks “upwards” the component tree (starting from leaf towards the root) and takes the first provider it finds. If an instance for this provider was already created previously, this instance is used, otherwise a new instance is created.

For e.g. In the bbelow sample we have hirerachy of components in this manner

App Component => Parent Component => Child Component => Grand Child component

Comp-Hirerarchy1

All the components share a Utility Service which looks some thing like this 

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

@Injectable()
export class UtilityService {
  public currentDateTime : Date;
  constructor() { 
    console.log("Inside Utility Service Constructor");
    this.currentDateTime = new Date();
  }

}

As you can see service is not doing any thing special it just has a date time variable which gets initialized when instance of that service is created.

These components are rendered dynamically based on button clicks in following sequence
Comp-Hirerarchy2

Click on Show hide it renders the Parent component, in this case parent component is using same instance as that of App Component, it is had not provided its own provider. So the date time which is displayed is same in app and parent component.

Comp-Hirerarchy3

Click on show hide of parent component it renders Child Component, not in this case it will display a new date time as we have specified provider of Utility service inside Child Component.

Comp-Hirerarchy4

import { Component, OnInit } from '@angular/core';
import { UtilityService } from './../services/utility.service';
@Component({
  selector: 'app-child',
  templateUrl: './child.component.html',
  styleUrls: ['./child.component.css'],
  providers: [UtilityService]
})
export class ChildComponent implements OnInit {
  public currentDateTime : string;
  constructor(private utilService: UtilityService) {
    this.currentDateTime = this.utilService.currentDateTime.toISOString();
   }

  ngOnInit() {
  }
}

Now the grand child component is not defining it own provider, so it is using the same instance as that of its ancestor which in this case is child component. So the date time which is displayed in the child component and grand child component is same.

Providers are usually singleton (one instance) objects, that other objects have access to through dependency injection (DI).  Provider is Angular’s term for these reusable objects (dependencies).

Provider lookup – When a component or directive has a dependency (constructor parameter), DI starts looking on this components injector for providers, if it has one it requests the instance from this provider and injects it. If the injector doesn’t have a provider for the requested key (type) then the parent injector is visited, up to the root (bootstrap) until a provider is found and its instance can be injected. (if no provider is found DI throws an error).

We often declare providers in angular this way:

providers: [AnyService]

Which is short cut for representing this

[new Provider(AnyService, {useClass: AnyService})]

 

Complete source code can be found at Github

Angular 2 Nested Routing – Demo

Angular 2 routing supports nested routing which was kind of lacking in Angular 1.*, unless you use UI-Router in Angular 1. Nested routing can be achieved in Angular using the Component router, which is pretty powerful and configurable and most of all supports deep nested routing, using the component router, you can declaratively specify application states, manage state transitions while taking care of the URL, and load bundles on demand. This blog post will cover how to set up the nested routing, it includes nesting up to 3 levels, but you can do much deeper nesting as well.

So this demo looks some thing like this

nested-routing-1

nested-routing-2

Essentially we have an app (which is a a component) which has following 2 components (child components)

  • Customers – This component has further child components
    • Customers List
    • Prospect Customers
    • Inquiries
  • Orders – This component has further child components
    • Completed Orders
    • In Progress Orders

Lets looks at first app component and lets set up the Main navigation, here is how the app component html looks like, left is navigation area and right is the router outlet where either orders or customer component will be displayed depending upon the route selection.

router-outlet:  It acts as a placeholder that Angular dynamically fills based on the current router state.

nested-routing-3

In the app module we need to define  the routes, here is how the app module looks like

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';
import { RouterModule, Route } from '@angular/router';
import { CustomersModule } from './customers/customers.module';
import { OrdersModule } from './orders/orders.module';
import { CustomersComponent } from './customers/customers.component';
import { OrdersComponent } from './orders/orders.component';
import { AppComponent } from './app.component';
const appRoutes = [
  {
    path: 'customers',
    component: CustomersComponent,
    loadChildren: './customers/customers.module#CustomersModule',
    data: { preload: true }
  },
  {
    path: 'orders',
    component: OrdersComponent,
    loadChildren: './orders/orders.module#OrdersModule',
    data: { preload: true }

  },
  {
    path: '',
    redirectTo: '/customers',
    pathMatch: 'full',
  },
]
@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule, FormsModule, HttpModule, CustomersModule, OrdersModule,
    RouterModule.forRoot(appRoutes)
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

 

As you can see we have defined the routes to load Orders and Customers component as well as redirect to customers component by default in case of empty route path.

Also please note the RouterModule.forRoot(appRoutes),  this configures the routing for root module.

RouterModule can be imported multiple times: once per lazily-loaded bundle. Since the router deals with a global shared resource–location, we cannot have more than one router service active. That is why there are two ways to create the module:

  • RouterModule.forRoot
    • forRoot creates a module that contains all the directives, the given routes, and the router service itself.
  • RouterModule.forChild.
    • forChild creates a module that contains all the directives and the given routes, but does not include the router service.

When registered at the root, the module should be used as RouterModule.forRoot as shown in the app module above. For submodules and lazy loaded submodules the module should be used as RouterModule.forChild as shown below for CustomersModule or OrderModules.

loadChildren is a reference to lazy loaded child routes. In the above case if loadChildren is not specified then when user hits http://localhost:4200 then it routes to http://localhost:4200/customers, and displays the customers component but does not load the child components. When we specify loadChildren then it loads the child component.

For loadChildren Angular will fetch the module at the location and then load the routes defined in its router config. The path to the file and name of the module is separated by #. The Router reads the ModuleName given after # and loads the module accordingly. So we did not load CustomersModule and OrdersModule in our AppComponent, instead used loadChildren property in the routing config to lazy load our modules.

By default it loads customer component in the main area, so lets look at the customer component, here is how the html for customer component looks like

nested-routing-4.JPG

Customers List, Prospect Customers and Inquiries are the bootstrap tabs, clicking on those loads respective component in the router-outlet area.

Here is how the customer module looks like

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule, Route } from '@angular/router';
import { CustomersComponent } from './customers.component';
import { CustomersListComponent } from './customers-list/customers-list.component';
import { ProspectsComponent } from './prospects/prospects.component';
import { InquiriesComponent } from './inquiries/inquiries.component';
import { CustomersService } from "./customers.service";
const customersRoutes = [
  {
    path: 'customers',
    component: CustomersComponent,
    children: [
      {
        path: '',
        redirectTo: '/customers/list',
        pathMatch: 'full',
      },
      {
        path: 'list',
        component: CustomersListComponent
      },
      {
        path: 'prospects',
        component: ProspectsComponent
      },
      {
        path: 'inquiries',
        component: InquiriesComponent
      }
    ]
  }
]
@NgModule({
  imports: [
    CommonModule,
    RouterModule.forChild(customersRoutes)
  ],
  declarations: [CustomersComponent, CustomersListComponent, ProspectsComponent, InquiriesComponent],
  providers: [CustomersService]
})
export class CustomersModule { }

 

Over here we are defining routes to load child components of customers component.

Please note RouterModule.forChild(customersRoutes), this configures the child routes for Customer component.

We are also redirecting to Customers list component by default in case of empty routes. So when user hits the URL http://localhost:4200/ app module routing redirects to http://localhost:4200/customers as well as tells to load child components as mentioned above not in the customers component we have a redirect specified that in case of empty route redirect to ‘/customers/list‘ i.e. http://localhost:4200/customer/list.

Screen shot for customers list is covered above,below one shows child components (Prospect and Inquiries respectively).

nested-routing-5nested-routing-6

Similar to customers component Orders Component has its own child component, here is how the html looks like

nested-routing-7

and its module looks some thing like this

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule, Route } from '@angular/router';
import { OrdersComponent } from './orders.component';
import { CompletedOrdersComponent } from './completed-orders/completed-orders.component';
import { InProgressOrdersComponent } from './in-progress-orders/in-progress-orders.component';
import { OrdersService } from './orders.service';
const ordersRoutes = [
  {
    path: 'orders',
    component: OrdersComponent,
    children: [
      {
        path: '',
        redirectTo: '/orders/completed',
        pathMatch: 'full',
      },
      {
        path: 'completed',
        component: CompletedOrdersComponent
      },
      {
        path: 'inprogress',
        component: InProgressOrdersComponent
      }
    ]
  }
]
@NgModule({
  imports: [
    CommonModule,
    RouterModule.forChild(ordersRoutes)
  ],
  declarations: [OrdersComponent, CompletedOrdersComponent, InProgressOrdersComponent],
  providers: [OrdersService]
})
export class OrdersModule { }

Screen shot for Completed orders is covered above,below one shows in-progress orders child components.

nested-routing-9

Complete source can be found on GitHub

Angular 2 Pipes – Force Angular 2 to execute Pipe

Earlier in the blogs we had seen samples of Pipes, I am referring to the sample example below again. Below is the grid for displaying list of persons and as you type in the something in multiple filters like name, email and company, that filter criteria will get applied to that persons data and filter the grid items.

blog-oioe-multiple-params-2

blog-oioe-multiple-params-3

Below is the pipes transform implementation

import {Pipe, PipeTransform } from '@angular/core';
@Pipe({
    name: 'personSearch'
})
export class PersonSearchPipe implements PipeTransform {
    transform(items: Array, nameSearch: string, emailSearch: string, companySearch: string){
        if (items && items.length){
            return items.filter(item =>{
                if (nameSearch && item.name.toLowerCase().indexOf(nameSearch.toLowerCase()) === -1){
                    return false;
                }
                if (emailSearch && item.email.toLowerCase().indexOf(emailSearch.toLowerCase()) === -1){
                    return false;
                }
                if (companySearch && item.company.toLowerCase().indexOf(companySearch.toLowerCase()) === -1){
                    return false;
                }
                return true;
           })
        }
        else{
            return items;
        }
    }
}

You need to register the pipes with the module

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';

import { AppComponent } from './app.component';
import { PersonSearchPipe } from './personSearch.pipe';
@NgModule({
  declarations: [
    AppComponent,
    PersonSearchPipe
  ],
  imports: [
    BrowserModule,
    FormsModule,
    HttpModule
  ],
  providers: [],
  bootstrap: [AppComponent],

})
export class AppModule { }

blog-oioe-multiple-params-1

In the above grid for displaying list of persons and as you type in the something in multiple filters like name, email and company, that filter criteria will get applied to that persons data and filter the grid items. This works perfectly fine but what if he an item is added to the filter list which matches the filter criteria then this item will not be appended to the filter list, for that to happen we have to replace the array by creating a copy of it and assigning it back to the components persons array which does not seem to be very intuitive way of doing it.

Here is the component code, I have added a setInterval which appends the person item to the array every 5 seconds on the

 ngOnInit() {
    setInterval(() => {
      this.ngzone.run(() => {
        let person = JSON.parse(JSON.stringify(this.persons[0]));
        this.persons.push(person);
        console.log("Length: " + this.persons.length);
      })
    }, 5000)
  }

Now when we have applied filter these appended elements will not be available in the UI as the pipes are not executing , so work around this we can force the pipe to be executed, this can be achieved by adding the fake filter like date time or random number to the pipe and assign the new value every time. In the above scenario I will add the Datetime to the component and pass the same to Pipe, below is the ngOnInit code

 ngOnInit() {
    setInterval(() => {
      this.ngzone.run(() => {
        let person = JSON.parse(JSON.stringify(this.persons[0]));
        this.persons.push(person);
        this.currentDatetime = new Date();
        console.log("Length: " + this.persons.length);
      })
    }, 5000)
  }

Here is the updated pipe code

import {Pipe, PipeTransform } from '@angular/core';
@Pipe({
    name: 'personSearch'
})
export class PersonSearchPipe implements PipeTransform {
    transform(items: Array<any>, nameSearch: string, emailSearch: string, companySearch: string, currentDatetime: Date){
        if (items && items.length){
            return items.filter(item =>{
                if (nameSearch && item.name.toLowerCase().indexOf(nameSearch.toLowerCase()) === -1){
                    return false;
                }
                if (emailSearch && item.email.toLowerCase().indexOf(emailSearch.toLowerCase()) === -1){
                    return false;
                }
                if (companySearch && item.company.toLowerCase().indexOf(companySearch.toLowerCase()) === -1){
                    return false;
                }
                return true;
           })
        }
        else{
            return items;
        }
    }
}

here is the updated Html

blog-force-pipe-to-execute-1

Now your filter will work like charm, as u can see “Johanna Chaney” person getting appended.

blog-force-pipe-to-execute-2

Here is the attached source code 

 

Angular 2 – Pipes passing multiple filters to Pipes

In earlier blog posts we had seen simplistic scenario of using pipes, but what if there is requirement to pass multiple parameters to Pipes in Angular 2,below example demonstrates the same.

Below is the grid for displaying list of persons and as you type in the something in multiple filters like name, email and company, that filter criteria will get applied to that persons data and filter the grid items.

blog-oioe-multiple-params-2

blog-oioe-multiple-params-3

For creating custom pipes you need to create class that implements PipeTransform Interface, this class is then decorated with @Pipe decorator. From the PipeTranform interface you need to implement transform method,  for passing multiple filter parameters to the pipe in the transform method you need to add those parameters like shown below in the code snippet. (nameSearch: string, emailSearch: string, companySearch: string). Transform method implementation then can decide the filtering based on the parameters passed, you can implement your own custom logic over here.

import {Pipe, PipeTransform } from '@angular/core';
@Pipe({
    name: 'personSearch'
})
export class PersonSearchPipe implements PipeTransform {
    transform(items: Array, nameSearch: string, emailSearch: string, companySearch: string){
        if (items && items.length){
            return items.filter(item =>{
                if (nameSearch && item.name.toLowerCase().indexOf(nameSearch.toLowerCase()) === -1){
                    return false;
                }
                if (emailSearch && item.email.toLowerCase().indexOf(emailSearch.toLowerCase()) === -1){
                    return false;
                }
                if (companySearch && item.company.toLowerCase().indexOf(companySearch.toLowerCase()) === -1){
                    return false;
                }
                return true;
           })
        }
        else{
            return items;
        }
    }
}

You need to register the PersonSearchPipe to component module like show below

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';

import { AppComponent } from './app.component';
import { PersonSearchPipe } from './personSearch.pipe';
@NgModule({
  declarations: [
    AppComponent,
    PersonSearchPipe
  ],
  imports: [
    BrowserModule,
    FormsModule,
    HttpModule
  ],
  providers: [],
  bootstrap: [AppComponent],

})
export class AppModule { }

 

In the HTML for the component add the filter like shown below

blog-oioe-multiple-params-1

 

 

Angular 2 – Passing data to child components

It is very common requirement to pass the data from Parent component to child component. In angular this can be achieved using using the @Input decorator, to define an input for a component, we use the @Input decorator. This decorator tells Angular to treat passed value as an input binding

Below is the Partner Component which has child component Partner contacts, their HTML looks some thing like this
Partner Component

{{partner.name}} {{partner.website}}
<app-partners-contacts-list [contacts]="partner.contacts"></app-partners-contacts-list>

Inside partner component we have child component partner contact list

<app-partners-contacts-list [contacts]="partner.contacts"></app-partners-contacts-list>

Partner Contact List: As u can see for the child component we are setting the partner.contacts array value to the the contacts @Input property on the child component. Child component looks some thing like this

import { Component, OnInit, Input } from '@angular/core';
import { PartnerContacts } from './../../partner.model';
@Component({
  selector: 'app-partners-contacts-list',
  templateUrl: './partners-contacts-list.component.html'
})
export class PartnersContactsListComponent implements OnInit {
  @Input() contacts: PartnerContacts[];
  constructor() { }

  ngOnInit() {
    console.log(this.contacts);
  }

}

As you can see we have declared an @Input property inside the child component so that we can set the this value from parent component.

HTML : It just a table iterating through contacts array.

Angular 2 Custom Pipes

In Angular 1.x we had used Filters extensively be it inbuilt ones or the custom ones. In Angular 2.x filters have been re-branded/renamed to Pipes. Below is an example for building custom pipes in Angular 2.x.

Below is the grid for displaying list of persons and as you type in the something in search criteria it will apply that filter criteria to person name property and filter the grid items.

personlist

personfilteredlist

For creating custom pipes you need to create class that implements PipeTransform Interface, this class is then decorated with @Pipe decorator. From the PipeTranform interface you need to implement transform method, below is the code snippet for the same.

import {Pipe, PipeTransform } from '@angular/core';
@Pipe({
    name: 'personSearch'
})
export class PersonSearchPipe implements PipeTransform {
    transform(items: Array, searchValue: string){
        if (searchValue){
            return items.filter(item =>{
                if (item.name.indexOf(searchValue) > -1){
                    return true;
                }
                return false;
           })
        }
        else{
            return items;
        }
    }
}

You need to register the PersonSearchPipe to component module like show below

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';

import { AppComponent } from './app.component';
import { PersonSearchPipe } from './personSearch.pipe';
@NgModule({
  declarations: [
    AppComponent,
    PersonSearchPipe
  ],
  imports: [
    BrowserModule,
    FormsModule,
    HttpModule
  ],
  providers: [],
  bootstrap: [AppComponent],

})
export class AppModule { }

 

In the HTML for the component add the filter like shown below

personlisthtml

Attached is the source code over here, to run the source please set up angular-cli and do npm install