05 March 2016

This is an introduction to Pipes in AngularJS 2. Please read on if you want to know more on Pipes(Angular2) and Filters(Angular1.x). This blog contains examples on Pipes and Filters done in ES6.

What is the Pipe?

Yes, We are talking about last one from above. In computer programming, especially in UNIX operating systems, a pipe is a technique for passing information from one program process to another. Unlike other forms of interprocess communication (IPC), a pipe is one-way communication only. Basically, a pipe passes a parameter such as the output of one process to another process which accepts it as input. The system temporarily holds the piped information until it is read by the receiving process.

program1 output >> program2 input

The grep Command in UNIX

The simplest use of grep is to look for a pattern consisting of a single word. It can be used in a pipe so that only those lines of the input files containing a given string are sent to the standard output. If you don't give grep a filename to read, it reads its standard input; that's the way all filter programs work.


$ls -l | grep "Aug"
-rw-rw-rw-   1 samy  doc     11008 Aug  6 14:10 ch02
-rw-rw-rw-   1 samy  doc      8515 Aug  6 15:30 ch07
-rw-rw-r--   1 john  doc      2488 Aug 15 10:51 intro
-rw-rw-r--   1 mira  doc      1605 Aug 23 07:35 macros

What is the Filter?

Now, we know what is Pipe and how it works in UNIX. This Pipe is formerly known as filters in AngularJS 1.x. In Angular 1 we had filter which helped format, sort or transform how data was displayed in our templates. Filters can be used with a binding expression or a directive. In Angular 2 we have a very similar feature but renamed to Pipes. This rename was to better align of what the feature does. Coming from the Unix background we | pipe together commands. So in Angular we use the same | pipe character to format our data.

Angular 2 has many new concepts and some of the same concepts from Angular 1.x. Many of the filters from Angular 1.x carry over to pipes in Angular 2.0, but we also get some new ones. Angular 1.x and Angular 2 have an equal number of filters to pipes, but there isn't direct crossover.

The following table shows a comparison:
Filter/Pipe Name Angular 1.x Angular 2
currency
date
uppercase
json
limitTo
lowercase
number
orderBy
filter
async
decimal
percent
slice
replace
I18nSelect
I18nPlural

Formatting Data with Filters in AngularJS 1.x

Filters allow you to declare how to transform data for display to the user within an interpolation in your template. The syntax for using filters is:


{{ expression | filterName : parameter1 : ...parameterN }}

where expression is any Angular expression, filterName is the name of the filter you want to use, and the parameters to the filter are separated by colons. The parameters themselves can be any valid Angular expression.
Angular comes with several filters, like following,

Following is an example of currency filter :

{{12.9 | currency}}
This bit of code will display the following:
$12.90

We put this declaration in the view (rather than in the controller or model) because the dollar sign in front of the number is only important to humans, and not to the logic we use to process the number.

Filters can also be chained with additional pipe symbols in the binding. For example, we can format the previous example for no digits after the decimal by adding the number filter, which takes the number of decimals to round to as a parameter. So:


{{12.9 | number:0 | currency}}
displays:
$13.00

Sorting Data with Filters in AngularJS 1.x

The orderBy filter allows us to sort an array. By default, strings are sorted alphabetically, and numbers are sorted numerically. The syntax for using orderBy filter is:


{{ orderBy_expression | orderBy : expression : reverse}}

The expression used to determine the order. The expression can be of type String or Function or Array. The array items can be both strings and functions. The reverse is optional. To sort in ascending order, set reverse to false. To sort in descending order, set reverse to true. You can also use + and - to sort in ascending and descending order respectively.

Following is an example of orderBy filter :

ng-repeat="student in students | orderBy:'scholorship':false"
			OR
ng-repeat="student in students | orderBy:'+scholorship'"
This bit of code will sort list of student in scholorship's ascending order.

Custom Filters The Angular 1.x way

You’re not limited to the bundled filters, and it is simple to write your own. If we wanted to create a filter that title-cased strings for our headings, for example, we could do so as follows:


var homeModule = angular.module('HomeModule', []);
homeModule.filter('titleCase', function() {
  var titleCaseFilter = function(input) {
    var words = input.split(' ');
    for (var i = 0; i < words.length; i++) {
      words[i] = words[i].charAt(0).toUpperCase() + words[i].slice(1);
    }
    return words.join(' ');
  };
  return titleCaseFilter;
});

With a template like this:

<body ng-app='HomeModule' ng-controller="HomeController">
  <h1>{{pageHeading | titleCase}}</h1>
</body>

and inserting the pageHeading as a model variable via a controller:

function HomeController($scope) {
  $scope.pageHeading = 'behold the majesty of your page title';
}

we would see something resembling like following.

Behold The Majesty Of Your Page Title

Source code of Angular 1.X filters is available here.

Why pipes?

AngularJS 1.x has a filter called filter, which allows us to do sort, format and transform. However, the duplication of the names often leads to confusion. That's another reason the core team renamed the filter component to pipe. Pipes don’t give you any new feature. In angular 2 you can use logics in templates too. You also can execute a function in the template to get its returned value. But pipes is a beutiful way to handle these things in templates. It makes your code more clean and structured.
Angular 2 comes with several pipes, like following,

Formatting Data with Pipes in AngularJS 2.0

The responsibility for formatting data in AngularJS 1.x was assigned to filters. Another example for a data formatting requirement is when we use collections of items. For instance, if we have a list of items, we may want to filter it based on a predicate (a boolean function); in a list of numbers, we may want to display only prime numbers, Pipe or Filter is hero here.

The motivation behind the new name is the syntax used for pipes and filters:


{{expression | decimal | currency}}

In the preceding example, we apply the pipes, decimal and currency, to the value returned by expression. The entire expression between the curly braces looks like Unix pipe syntax.

Lets look at a simple pipe built into Angular 2 the date pipe. The date pipe simply formats our date in our templates.


{{date | date:'shortDate'}}
{{date | date:'longDate'}}

The date Wed May 3 2016 22:01:58 GMT-0600 (Central Standard Time) would be formated to 5/3/2016 and May 3, 2016.

Custom Pipes The Angular 2.0 way

The syntax for defining pipes is similar to the one used for the definition of directives and components. In order to create a new pipe, all we need to do is to provide a name for the pipe and define the data formatting logic. During runtime, once the Angular 2 expression interpreter finds out that a given expression includes a call of a pipe, it will retrieve it out of the pipes collection allocated within the component and invoke it with the appropriate arguments.

The following example illustrates how we can define a simple pipe called lowercase1, which transforms the given string, passed as argument to its lowercase representation:


var LowercasePipe1 = ng.core.
  Pipe({
    name: 'lowercase1'
  })
  .Class({
    constructor: function () {},
    transform: function (value) {
      if (!value) return value;
      if (typeof value === 'string') {
        throw new Error('Invalid pipe value', value);
      }
	return value.toLowerCase();
    }
  });

Now let's demonstrate how we can use the lowercase1 pipe inside a component:


var App = ng.core.Component({
  selector: 'app',
  pipes: [LowercasePipe1],
  template: '<h1>{{"SAMPLE" | lowercase1}}</h1>'
})
.Class({
  constructor: function () {}
});

We can use the App component with the following markup:

<app></app>

Source code of Angular 2 pipes is available here.

Stateful and Stateless Pipes

There are two categories of pipes, stateless and stateful. Stateless pipes are pure and Stateful pipes are impure. Before going ahead with stateless and stateful, Let us go through pure and impure.

Pure and Impure Pipes

There are two categories of pipes: pure and impure. Pipes are pure by default. Every pipe we've seen so far has been pure. We make a pipe impure by setting its pure flag to false. By setting pure property in pipe, we can declare whether we want the pipe it implements the logic for to be either stateful or stateless.

Following is syntax for pure property :

Pipe({
    name: 'pipeName',
    pure: false
  })

The pure property is important, because in case the pipe is pure, the change detection can be optimized. Angular looks for changes to data-bound values through a change detection process that runs after every JavaScript event: every keystroke, mouse move, timer tick, and server response. This could be expensive. Angular strives to lower the cost whenever possible and appropriate. Angular picks a simpler, faster change detection algorithm when we use a pipe.

Pure pipes :
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). Angular ignores changes within (composite) objects. It won't call a pure pipe if we change an input month, add to an input array, or update an input object property. This may seem restrictive but is is also fast. An object reference check is fast — much faster than a deep check for differences — so Angular can quickly determine if it can skip both the pipe execution and a view update. For this reason, we prefer a pure pipe if we can live with the change detection strategy. When we can't, we may turn to the impure pipe.

Impure pipes :
Angular executes an impure pipe during every component change detection cycle. An impure pipe will be called a lot, as often as every keystroke or mouse-move. With that concern in mind, we must implement an impure pipe with great care. An expensive, long-running pipe could destroy the user experience.

Stateless pipe

Stateless pipes are pure types that flow input data through without remembering anything or causing detectable side-effects. Most pipes are stateless. There was one common property between all the pipes mentioned earlier—all of them return exactly the same result each time we apply them to the same value and pass them the same set of arguments. Such pipes that hold the referentially transparency property are called pure pipes. The DatePipe we used and the LowercasePipe1 pipe we created both are examples of a stateless pipe.

Source code of stateless pipe's example is available here.

Stateful pipe

Stateful pipes are those which can manage the state of the data they transform. A pipe that creates an HTTP request, stores the response and displays the output, is a stateful pipe. Stateful Pipes should be used cautiously, as we know it is impure pipe.

The Angular AsyncPipe is an interesting example of an impure pipe as well as stateful. The AsyncPipe accepts a Promise or Observable as input and subscribes to the input automatically, eventually returning the emitted value(s). The AsyncPipe maintains a subscription to the input and its returned values depend on that subscription.

Source code of stateful pipe's example is available here.

Pipe vs filter

Angular 1.X had a concept of filters. Pipes are very much similar to that but it has some significant advantages, the pipes.
Filters used to act like helpers, very similar to functions where you pass the input and other parameters and it returns you the value; but pipe works as a operator. The concept is, you have an input and you can modify the input applying multiple pipes in it. This not only simplifies the nested pipe logic, but also gave you a beautiful and clean syntax for your templates. Secondly, in case of async operations, you need to set things manually in case of angular 1.X filters. But pipes are smart enough to handle async operations.

References :

  1. wikipedia.org wiki pages for Pipe
  2. "AngularJS" Author Brad Green, Shyam Seshadri and Published by O’Reilly Media, Inc.
  3. "Switching to Angular 2" Author Minko Gechev and Published by Packt Publishing Ltd.
  4. Angular 2 Series - Part 1: Working with Pipes by Ryan Chenkie
  5. Angular 2 pipes in depth; with list of inbuilt pipes and examples by Paul Shan