Observations

Ionic app development & related technologies

Understanding Angular pipes

August 2, 2017, 12:00 pm Categories:

Categories

Angular, the underlying front-end development framework used by Ionic, provides developers with a feature known as pipes which allows data values to be transformed within an application's template view prior to being displayed.

Such transformations might entail, for example, displaying dates in a particular format or ensuring that numeric values are consistently rounded up to a specific decimal place.

If, for example, we wanted to make a particular string value lowercase we could make use of the built-in LowerCasePipe like so:

Name is: {{ name.value | lowercase }}

A pipe is structured in the following way:

  • Use of interpolation braces to render a value inside the template view
  • The value to be rendered is placed on the left followed by a pipe character
  • The pipe used to transform the value is placed on the right of the pipe character

Developers can make use of built-in, pre-existing pipes or create their own custom pipes as and where the situation requires.

What we'll be exploring

Over the course of this tutorial I'm going to take you through using the following Angular pipes:

  • DatePipe
  • i18nSelect

Following from these we'll then create 2 custom pipes which will allow the following data transformations to take place:

  • Return a random array element
  • Return a random generated, unique string value with a name spliced into that at select intervals

We WON'T be discussing pure and impure pipes - as this is a little higher level than I want to spend time discussing in this tutorial - although you can learn more about what these are and how they work if you want to.

Let's start with exploring the aforementioned built-in pipes and seeing how these can be used within a template view.

Before we begin

The following tutorial assumes you are using the latest version of Ionic (which, at the time of writing, is Ionic 3.6) and that all examples will be executed inside your system browser using the ionic serve command.

Go ahead and fire up your command line utility and create a new Ionic project with the following:

ionic start ionic-pipes blank

You won't need to install any platforms, additional plugins or node modules once the project has been created - you can simply start coding based on the examples we're going to go through shortly.

Date formatting

One of the most useful pipes provided by Angular is the DatePipe which (as you probably guessed from the name) allows a date value to be formatted according to a set of supplied rules.

The date value must be supplied in one of the following formats:

  • JavaScript date object (I.e. new Date())
  • ISO string (An agreed method of representing date/time information in the following format: "YYYY-MM-DD)
  • Unix epoch time (the number of seconds that have elapsed since 00:00:00 Coordinated Universal Time (UTC), Thursday, 1 January 1970, minus the number of leap seconds that have taken place since then)

Predfined formatting options, supplied by the DatePipe, for displaying the date are as follows:

Option Result (for en-US locale)
medium Sep 3, 2010, 12:05:08 PM
short 9/3/2010, 12:05 PM
fullDate Friday, September 3, 2010
longDate September 3, 2010
mediumDate Sep 3, 2010
shortDate 9/3/2010
mediumTime 12:05:08 PM
shortTime 12:05 PM

Additional custom formatting options are also available allowing developers to fine tune the rendered date value:

Option Symbol
Era G
year y
month M
day d
weekday E
hour j
12 hour h
24 hour H
minute m
second s
timezone z
timezone Z
timezone a

Let's play with some of these shall we?

Within the ionic-pipe/src/pages/home/home.ts component class we'll use the JavaScript Date object to return the number of milliseconds elapsed since 1 January 1970 00:00:00 UTC and assign this to a public property of today:

import { Component } from '@angular/core';
import { NavController } from 'ionic-angular';

@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage {

   public today : number 	= Date.now();
   
   constructor(public navCtrl: NavController) 
   {
     
   }

}

Inside the src/pages/home/home.html template we can then format and render the today property value using the predefined medium format from the DatePipe class like so:

<p>Today is {{ today | date: 'medium' }}</p>

// This would render the following value:
Today is Jul 31, 2017, 4:51:22 PM

We could, of course, change the formatting option for the pipe to use combinations such as the following:

<p>Today is {{ today | date: 'shortDate' }}</p>

// Renders the following value:
Today is 7/31/2017



<p>Today is {{ today | date: 'fullDate' }}</p>

// Renders the following value:
Today is Monday, July 31, 2017



<p>Today is {{ today | date: 'EEEE MMMM d y h:m:ss a Z' }}</p>

// Renders the following value:
Today is Monday July 31 2017 3:38:21 PM GMT+1

As you can see the DatePipe provides developers with lots of flexibility for transforming date values in template views (and there's definitely more we could explore and experiment with while using this particular pipe).

Let's now take a look at filtering a JavaScript object using the i18nSelectPipe.

Filtering objects

The I18nSelectPipe allows a supplied value to be used as a key to filter through a JavaScript object.

This could be useful when multiple values are available and we need to filter through these by a specific key in order to display the correct value.

Let's see how this works by adding the following to the ionic-pipe/src/pages/home/home.ts component class:

public technology          : string = 'Ionic';
public technologyObj 	   : any 	= {'Ionic'          : 'Builds Mobile Apps', 
                                       'Angular'        : 'Front-end development framework', 
                                       'Apache Cordova' : 'The native wrapper',
                                       'other'          : 'Modern standards all round baby!'};

Inside the ionic-pipe/src/pages/home/home.html the key/value pairs of the technologyObj property will be filtered, thanks to the i18nSelectPipe, with a supplied value to check whether this matches any of the contained keys.

If no match is found then the i18nSelectPipe simply defaults to selecting the 'other' key of the technologyObj property instead:

<p>Technology is {{ technology }} - {{ technology | i18nSelect: technologyObj }}</p>

// Outputs:
Technology is Ionic - Builds Mobile Apps

That's a useful filtering function (and there IS a reason why Angular does not supply an explicit filter pipe) that we could definitely explore a lot further but let's move now to working with our own custom generated pipes.

Creating our own pipes

Within the root directory of the ionic-pipes project run the following commands using the Ionic CLI:

ionic g pipe custom
ionic g pipe rating

This will create an ionic-pipes/src/pipes directory with the following assets:

  • Custom directory - contains the CustomPipe class
  • Random directory - contains the RandomPipe class
  • pipes.module.ts

The pipes.module.ts file is simply a feature module where ALL of the generated pipes are imported and configured allowing them to be lazy loaded for use in the application:

import { NgModule } from '@angular/core';
import { RandomPipe } from './../pipes/random/random';
import { CustomPipe } from './../pipes/custom/custom';
@NgModule({
	declarations: [RandomPipe,
    CustomPipe],
	imports: [],
	exports: [RandomPipe,
    CustomPipe]
})
export class PipesModule {}

In order to access these pipes in the project we need to import the PipesModule into each component module where we want to access and implement those pipes.

Currently we only have the HomePage component and (as of Ionic 3.6) this doesn't have a component module generated by default.

Let's create one.

Lazy loading our pipes

In your favourite code editor create an ionic-pipes/src/pages/home/home.module.ts file containing the following code:

import { NgModule } from '@angular/core';
import { IonicPageModule } from 'ionic-angular';
import { HomePage } from './home';
import { PipesModule } from '../../pipes/pipes.module';

@NgModule({
  declarations: [
    HomePage,
  ],
  imports: [
    IonicPageModule.forChild(HomePage),
    PipesModule
  ],
  exports: [
    HomePage
  ]
})
export class HomeModule {}

Let's amend the ionic-pipes/src/pages/home/home.ts component class to allow that page component to be lazy loaded through use of a specific string identifier of ionic-pipes-home:

import { Component } from '@angular/core';
import { IonicPage, NavController } from 'ionic-angular';

@IonicPage({
	name : "ionic-pipes-home"
})
@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage {

   public today                : number 	= Date.now();
   public technology           : string 	= 'Ionic';
   public technologyObj 	   : any 		= {'Ionic'          : 'Builds Mobile Apps', 
                                               'Angular'        : 'Front-end development framework', 
                                               'Apache Cordova' : 'The native wrapper'};
   
   constructor(public navCtrl: NavController) 
   {
     
   }

}

Next you'll need to modify the project's root module - ionic-pipes/src/app/app.module.ts - to remove any HomePage imports and configurations like so:

import { BrowserModule } from '@angular/platform-browser';
import { ErrorHandler, NgModule } from '@angular/core';
import { IonicApp, IonicErrorHandler, IonicModule } from 'ionic-angular';
import { SplashScreen } from '@ionic-native/splash-screen';
import { StatusBar } from '@ionic-native/status-bar';

import { MyApp } from './app.component';

@NgModule({
  declarations: [
    MyApp
  ],
  imports: [
    BrowserModule,
    IonicModule.forRoot(MyApp)
  ],
  bootstrap: [IonicApp],
  entryComponents: [
    MyApp
  ],
  providers: [
    StatusBar,
    SplashScreen,
    {provide: ErrorHandler, useClass: IonicErrorHandler}
  ]
})
export class AppModule {}

Similarly the application's root component - ionic-pipes/src/app/app.component.ts - will need to be modified to "lazy load" the HomePage component like so:

import { Component } from '@angular/core';
import { Platform } from 'ionic-angular';
import { StatusBar } from '@ionic-native/status-bar';
import { SplashScreen } from '@ionic-native/splash-screen';

@Component({
  templateUrl: 'app.html'
})
export class MyApp {
  rootPage:any = 'ionic-pipes-home';

  constructor(platform: Platform, statusBar: StatusBar, splashScreen: SplashScreen) {
    platform.ready().then(() => {
      // Okay, so the platform is ready and our plugins are available.
      // Here you can do any higher level native things you might need.
      statusBar.styleDefault();
      splashScreen.hide();
    });
  }
}

With these modifications in place we can be sure that the necessary pipes and HomePage component can be lazy loaded, executed and rendered by the browser as required.

Cool!

Let's now move onto configuring the transformation logic for our recently generated pipes - starting with the RandomPipe class.

Random pipe

All pipes in Angular make use of a single method - transform - which, as the name implies, is used to provide the functionality for transforming data values prior to rendering those in the template.

Consequently we'll be working with this method to supply the necessary functionality within both our custom generated pipes.

With our ionic-pipe/src/pipes/random/random.ts pipe we are going to supply an array of data to the pipe which will then randomly select and return one item from that array.

The logic for returning a random array element is incredibly simple as you can see:

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

/**
 * Generated class for the RandomPipe pipe.
 *
 * See https://angular.io/docs/ts/latest/guide/pipes.html for more info on
 * Angular Pipes.
 */
@Pipe({
  name: 'random',
})
export class RandomPipe implements PipeTransform {
  
    transform(value : any) : any
   {
      return value[Math.floor(Math.random() * value.length)]
   }
   
}

Going back to the ionic-pipes/src/pages/home/home.ts component class add the following array just above the class constructor:

public technologies  : any        = ['Ionic',
                                     'Angular',
                                     'Apache Cordova',
                                     'TypeScript',
                                     'Sass',
                                     'HTML5'];

Then, within the ionic-pipes/src/pages/home/home.html template view, we'll randomly select one of the elements from this array using the RandomPipe logic like so:

<p>Random technology selection: {{ technologies | random }}</p>

// This will output something akin to the following (values are randomly assigned)
Random technology selection: HTML5

Our first custom generated pipe in action!

Not bad huh?

Custom piping

The functionality for the RandomPipe class was fun but a little limited.

Let's turn now to the ionic-pipe/src/pipes/custom/custom.ts pipe and craft some logic that will allow a random, unique string to be generated with the letters of a name spliced at 5 character intervals.

Sound like a challenge?

Let's explore how we're going to achieve this while being guided courtesy of the heavily commented script below:

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

/**
 * Generated class for the CustomPipe pipe.
 *
 * See https://angular.io/docs/ts/latest/guide/pipes.html for more info on
 * Angular Pipes.
 */
@Pipe({
  name: 'custom',
})
export class CustomPipe implements PipeTransform {


   // Supply a name value to the transform method which we'll subsequently splice 
   // into our randomly generated string
   transform(myName : any) : any
   {
      // List ALL of the alphanumeric characters we can draw on for generating a random string
      let chars     : string   = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789",

          // Variable for containing the value of the soon to be generated string
          randomStr    : string   = "",

          // Split the supplied name into an array
          splitStr     : any      = myName.split(""),

          // Define counters for array iteration
          i            : number,
          k            : number   = 0;

      // Iterate over the chars string
      for(i = 0; i < chars.length; i++) 
      {
         // Generate a random value
         var randomVal     = Math.floor(Math.random() * chars.length);

         // Retrieve a character from the chars string using this random value
         // and add this to the randomStr string to build up the unique, randomly 
         // generated string
         randomStr += chars.charAt(randomVal);

         // Use the modulo operator to insert a letter from the 
         // supplied name at 5 character intervals
         if(i % 4 === 2)
         {
            // IF the counter value is NOT equal to the length of the array
            // (as we DON'T want to generate undefined values if it is)
            if(k !== splitStr.length)
            {
               // Then add that letter from the splitStr array, convert it 
               // to uppercase and increment the counter by one
               randomStr += splitStr[k].toUpperCase() + chars.charAt(randomVal);
               k++;
            }
         }
      }
      
      // Return the uniquely generated string for embedding in the template view
      return randomStr;
   }


}

Within the ionic-pipes/src/pages/home/home.ts component class add the following property just above the class constructor (you can add what value you like here - I've simply used my name):

public str : string     =  'JamesGriffiths';

Inside the ionic-pipes/src/pages/home/home.html template we can then test whether the CustomPipe is working like so:

<p>Random string: {{ str | custom }}</p>

This should output something akin to the following:

// Random string #1
Random string: v8BJBdK9tAtUZZFMFT0OhEh2DkkSkgYGWGWJXXlRlKkqJIJAfxmFmqZusFsdirVIV8S4RTRR5PdHdYfhISIU8sisgR


// Random string #2
Random string: 9aeJevD0lAlbn2nMnowudEddlfMSMsUfbGbDutNRNLtZmImZkykFkdlHjFjrhMzIzmoCyTy5sOAHAIP5NSNFhpBFol


// Random string #3
Random string: qzgJgRNN7A7k8GqMqviWCECng9eSeiqw7G7OEVjRjIIE5I5rJFgFg1uzkFk3DdTITUyYnTngpOXHXei7HSHJIjCGlh

Notice that each letter of my name is spliced into the above random strings at the same intervals?

Not bad for a custom pipe!

In summary

Angular's pipes functionality provide a powerful way to transform values directly within the template views themselves - whether that's through using Angular's built-in pipes or our own custom generated pipes.

Ideally we should parse and transform values within the component class BEFORE we get to the template level but sometimes this just isn't possible.

Of course there are more built-in pipes offered by the angular framework than the ones I've covered in this tutorial and there's lots going on in the background with pipes which you can learn more about here.

Hopefully you've found the above tutorial useful and, if so, please feel free to share your comments, thoughts and suggestions in the comments area below.

I explore other areas of using the Ionic framework within my e-book featured below and if you're interested in learning more about my e-books please sign up to my FREE mailing list where you can receive updates on current/forthcoming e-books and blog articles.

Tags

Categories

Leave a comment

Feel free to share your thoughts, opinions and/or suggestions with regards to this blog article.

There's only one rule: Be nice - trolling others, behaving abusively or spamming the blog will result in your post being deleted.

Top