Click here to Skip to main content
15,886,422 members
Articles / Web Development / HTML

Learn Angular Tutorial - Part 6

Rate me:
Please Sign up or sign in to vote.
5.00/5 (4 votes)
8 Nov 2017CPOL8 min read 18.5K   269   14  
Pipes and Providers in Angular
This is Lab 6 of step by step Angular series. In this article, we will cover two important labs, Pipes and Providers.

Contents

Link to Rest of the Articles

  • In the first part, we look into Node, TypeScript, Module loaders/Bundlers and VS Code.
  • In the second article, we create a simple basic Angular application with a screen and we run through important concepts like components & modules.
  • In the third article, we look into implementing SPA and validations.
  • In the fourth article, we understand how to make HTTP calls and how to create custom Angular components using Input and Outputs.
  • In the fifth part, we cover two labs, one is how to use JQuery with Angular and Lazy routing.
  • In the sixth part, we again cover two labs - Pipes and DI using providers.

Introduction

In this article, we will cover two important labs, Pipes and Providers. Pipes help us to create reusable code by which we can format outputs and providers help us to create good architecture for Angular.

Lab 13: Pipes in Angular

This lab is the smallest of all labs till now with some theory followed by three steps. So if you are tired and worn out by now, this lab is like a restful lab.

Introduction

Pipes take in a data input and transform data to a different output. For example, pipe can take “Learn Angular” as input and transform to “LEARN ANGULAR” in capital or you can give input as “100” which you want to display (transform) as “100.00 $” on UI.

Image 1

So for this lab, we will do the following pipe transforms: -

  • Change Customer name into capital letters.
  • Change Customer amount to proper formatted amount with $ currency sign.
  • Depending on the Amount, we would like to display “Gold” or “Silver” customer status. So if the amount exceeds 100, it will display “Gold Customer” and if less than 100, it will display “Simple Customer”.

See the image for more details of how the output would look like.

Image 2

Understanding Syntax of Pipes

Before we move ahead with labs on pipes, let's understand how the syntax of pipes looks like. You need to write pipe syntax inside an expression “{{ }}”. You need to first put data that needs to be formatted and then followed by “|” symbol as shown in the below figure. Once you run it, it displays final formatted output on the HTML.

Pipe syntaxes are written inside HTML.

Image 3

Step 1: Applying Readymade Pipes

There are two broader categories of pipes: Readymade pipes and Custom pipes. You can get a list of readymade pipes from https://angular.io/api?type=pipe.

So to display “CustomerName” in capital and “CustomerAmount” with currency sign, we can use two readymade filters, “uppercase” and “currency” respectively. Below are the code syntaxes for the same:

JavaScript
{{CurrentCustomer.CustomerName | uppercase}}
JavaScript
{{CurrentCustomer.CustomerAmount | currency}}

Step 2: Creating Custom Pipes for Customer Grading

But the third requirement is a bit complicated. In this, if the entered amount is greater than 100, we need to display “Gold Customer” and if it’s less than 100, we need to display “Normal Customer”.

Image 4

So let’s create a separate folder called as “Pipes” and in that, let's create “GradePipes.ts” as shown in the below figure:

Image 5

In “GradePipes.ts”, we will write the code which will have the logic. So the first thing is that we need to import “Pipe” and “PipeTransform” from core as these classes are the building blocks for pipes.

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

The next thing is we need to create a “GradePipes” class which implements the “PipeTransform” interface and has “@Pipe” decorated on top of it. Every pipe class should have a “transform” method as it is small “t” “r”… “transform” which has an input parameter, i.e., customer amount which will be provided in the UI.

JavaScript
@Pipe({name: 'GradePipes'})
export class GradePipes implements PipeTransform {
  transform(value:number): string {
        if(value < 100){
            return "Simple Customer";
        }
        else{
            return "Gold Customer";
        }
  }
}

In “@Pipe” decorator, we have also specified a “name”. This name will be used in the UI to make a call to the pipe.

Step 3: Applying the Grading Pipe on the UI

And then, finally, we need to call the pipe in the HTML UI. We can now call “GradePipes” as shown in the below code. “CurrentCustomer.CustomerAmount” is the input and the pipe is “GradePipes”.

JavaScript
{{ CurrentCustomer.CustomerAmount|GradePipes}}

Once done, enjoy your output.

Image 6

Lab 14: Providers , Services and Dependency Injection

The Problem

Image 7

Courtesy: https://medium.com/nestle-usa/4-tips-for-starting-your-baby-on-fruits-veggies-aafd6b2c0cde

A sign of a good software architecture is:

“When you make change at one place, you do not need to change at many places”.

Now take the below situation. In your project, let’s say you have lot of modules and 100 (just put a figure 😊) components. Now in all your 100 components, you want to implement logging utility.

In logging utility also, you have different varieties. Some loggers just log to the console of the browser while some display using dialog boxes.

Image 8

So assume that these loggers are used in those 100s of components to log error and instrumentation messages. So in all your components, you will do two things:

  • Import the logger component using “import” syntax.
  • And then create object of the logger.

Below is the code snippet for it.

HTML
import { ConsoleLogger} from "../Utility/Utility"
// code deleted for clarity
export class CustomerComponent {
    logger: ConsoleLogger = new ConsoleLogger ();
    // code removed for clarity
}

Now let’s say somewhere down the line, you think you want to log messages using dialog boxes, think about the amount of changes you need to make in your 100 components.

Solution DI and IOC

Let's conclude what is the cause which leads to change in all components. To solve this problem, below is the solution, read the below sentence slowly with full senses alive.

“The problem is because Component is creating the object of Utility, if we can INVERT this, means if we can inject / provide “Utility” to the components rather than creating, then this will make our architecture better”.

Image 9

In other words, we need to implement “Inversion of control”. Means invert the object creation to someone else and component just refers a generic utility reference.

So rather than components creating the object of the utility, component will ASK for providing/ injecting the “logger” object via constructor.

Image 10

IOC is a concept and to implement IOC, we need to use DI. I would encourage you to see this Youtube video which explains DI and IOC in detail.

So now that we know DI and IOC concepts, let’s do a demonstration for the same.

Demo of DI IOC

Here is a simple demo we will implement in our project to see the importance of Provider DI. So we will create a simple parent “Logger” class and we will create two flavours, one which displays messages, one on dialog boxes and other to the console of the browser.

Image 11

We will then try to figure out how easy it is to make changes at one place and replicate it across all places.

Step 1: Create the Logger Utility Classes With Injectable Attribute

So let’s create a folder called as “Utility” inside which we will create these logger classes.

Image 12

Let’s create a parent “Logger” class from which we will inherit and create different flavours of “Logger” class. Now because this class will be injected in to the components, we need to mark it with “@Injectable()” decorator. “@Injectable()” decorator is available in “Injectable” in “angular/core”.

JavaScript
import { Injectable } from '@angular/core';
@Injectable()
export class Logger{
   public  Log(){
    // some default logging
   }
}

Below is the code for “ConsoleLogger” and “DialogLogger” classes which inherit from “Logger” class. For now, both classes do not have any functionality as such. At this moment, let's focus on DI rather than logging functionality.

JavaScript
@Injectable()
export class ConsoleLogger extends Logger{
    public Log(){
        // do console logging here
    }
}
@Injectable()
export class DialogLogger extends Logger{
    public Log(){
        // do console logging here
    }
}

Step 2: Define Providers and Injection in the Modules

So as we discussed previously, the goal is that we want to change at one place and the logger types should change in all components.

Now the whole loading (bootstrapping) of our project starts with “MainModuleLibrary”, so if we can inject at the level of “MainModuleLibrary’, it will be available to all components and modules down below.

Image 13

In the “MainModuleLibrary”, using “@NgModule” decorator, we need to provide the providers which will be trickled down to all components. In providers, we need to specify two things:

  • First, the parent class will be referred in all components. So using the “provide”, we have specified “Logger” class.
  • Second, we need to provide which child implementation object we want to inject in all components. That’s provided in “useClass”.
JavaScript
providers: [
      {
        provide: Logger,
        useClass: ConsoleLogger
      }
    ]

The complete code of the main module with “providers” looks something as shown below:

JavaScript
// Imports have been removed for clarity
import {Logger,DialogLogger,ConsoleLogger} from "../Utility/Utility"
@NgModule({
    imports: [RouterModule.forRoot(ApplicationRoutes), 
            HttpModule, 
            InMemoryWebApiModule.forRoot(CustomerApiService),
             BrowserModule,
             FormsModule,
             ReactiveFormsModule],
    declarations: [
                    MasterPageComponent,
                WelcomeComponent],
    bootstrap: [MasterPageComponent],
    providers: [
      {
        provide: Logger,
        useClass: ConsoleLogger
      }
    ]
})
export class MainModuleLibrary { }

Step 3: Define Constructors for Injection

Now that we have define on the main module which object will inject. In the components, we need to expose the “logger” class in the constructor for DI purpose.

Note: All your components should only refer “Logger” parent class and not the child classes. You can see in the below code that we have imported only “Logger” class and through constructor only “logger” class is referred.

JavaScript
// code removed for clarity
import {Logger} from "../Utility/Utility"
@Component({
    templateUrl: "../UI/Customer.html"
})
export class CustomerComponent {
    constructor(public http:Http , logger:Logger){
        this.Display();
    }
// code removed for clarity
}

Step 4: Test If Things Are Working

Run the application put a debug point and see the “ConsoleLogger” object getting injected. If you change it to “DialogLogger”, you will see the same injected.

Image 14

Take a deep breath, close your eyes and think. You are changing in the main module and it's getting propagated all over. As we started this lab saying a “Good architecture is all about changing at one place and the changes are reflected through out”.

Image 15

For further reading do watch the below interview preparation videos and step by step video series.

History

  • 8th November, 2017: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect https://www.questpond.com
India India

Comments and Discussions

 
-- There are no messages in this forum --