Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / AngularJs

Learn Angular in 10 days – Day 4 – Part 1

5.00/5 (4 votes)
19 Sep 2017CPOL5 min read 7.1K  
This is day 4 of the learn Angular in 10 days series

Finally completed Day 3. ??

C8

I have seen people getting scared because of long and big articles, hence I have decided to write multiple small articles for each day instead of writing one big article. In each article, we will cover 1 or 2 or max 3 labs.

In this lab, we will explore Angular Services.

Note: Before you proceed, make sure that your TypeScript compiler is executing in watch mode, and your web server is running. If you forgot how to do it, go with day 2 again.

Complete Series

  1. Day 1 – Part 1
  2. Day 1 – Part 2
  3. Day 2
  4. Day 3
  5. Day 4 – Part 1
  6. Day 4 – Part 2
  7. Day 4 – Part 3
  8. Day 5 (Coming soon)
  9. Day 6 (Coming soon)
  10. Day 7 (Coming soon)
  11. Day 8 (Coming soon)
  12. Day 9 (Coming soon)
  13. Day 10 (Coming soon)

 

Introduction to Angular Services

In Angular, Services represents the injectable application logic.

  • Technically, it will be a simple class encapsulating some king of logic. It can be any logic. It can be “a logic to make server call, a logic to create text file, logic to log messages”.
  • Injectable means – instances of those classes will not be created manually. Rather at run time, it will be created by Angular framework and make it available to other Application. This is called “Dependency Injection”.

Dependency injection or DI is not an Angular concept. It’s a design pattern. It says “Application will not create the Dependency instance. Instead, dependency instance will be injected into the application from outside by some Framework”. DI makes our application more loosely coupled and hence easy to test and extend in future. (After practical demonstration, it will be much clearer.)

All major technologies have support for implementing DI nowadays. These Technologies and frameworks have something called an “injector”. Injector at run time creates instance of dependency and make it available to the application.

Good news is, Angular has inbuilt support for Dependency injection which we will see in action very soon. Angular will create an application-wide “Angular injector” during the bootstrap process. Once the Angular Service is created, it will be registered with Angular injector. Angular injector creates the instance of this service and make it available to other parts.

Next two will make this concept very much clear.

Lab 11 – Decouple Application Logic from Component

In our project right now component specific logic and application logic both are written inside the same class that is “AppComponent” class.

As a best practice, we should take application specific logic out of the AppComponent class and should be put in some independent class. Instance of that class will be injected into “AppComponent” by Angular framework at runtime. In short, we have to implement DI in our Application.

Step 1 – Create Services Folder

Create a new folder called “Services” inside “AppModule” folder.

Step 2 – Create EmployeeService.

Now create a new TypeScript file called “EmployeeService.ts” in the “Services” folder.

Inside that TypeScript file, create a class “EmployeeService” as follows:

JavaScript
import {Employee} from "../Models/Employee"

export class EmployeeService{
     Employees:Array<Employee>;
      constructor(){
        this.Employees =new Array<Employee>();
        
        let e1=new Employee();;
        e1.FName="Sukesh";
        e1.LName="Marla";
        e1.Salary=10000;
        this.Employees.push(e1);

        let e2=new Employee();;
        e2.FName="Gabbar";
        e2.LName="Singh";
        e2.Salary=20000;
        this.Employees.push(e2);
        
        let e3=new Employee();;
        e3.FName="Dragon";
        e3.LName="Hunter";
        e3.Salary=30000;
        this.Employees.push(e3);
    }
    GetEmployees():Array<Employee>{
        return this.Employees;
    }
    SaveEmployee(e:Employee){
        this.Employees.push(e);
    }
}

It’s a simple class with two methods:

  • GetEmployees – Return the list of employees
  • SaveEmployee – Which will add new Employee to the existing collection

(It’s the same hard coded logic which is there in “AppComponent” class right now.)

Step 3 – Redefine AppComponent

Now it’s time to take application logic out of the AppComponent class.

Redefine it as follows:

JavaScript
import {Component} from "@angular/core"
import {Employee} from "../Models/Employee"
import {EmployeeService} from "../Services/EmployeeService"
@Component({
selector:'app-component',
templateUrl:'./app.component.html'
}
)
export class AppComponent{
    Employees:Array<Employee>;
    IsAddNew:boolean;
    constructor(private eLogic:EmployeeService){
        this.IsAddNew=false;
        this.Employees =this.eLogic.GetEmployees();
    }
    SaveEmployee():void{
       let e1=new Employee();
        e1.FName="F1";
        e1.LName="L1";
        e1.Salary=40000;
        this.eLogic.SaveEmployee(e1);
        this.IsAddNew=false;
    }
    ShowAddNew():void{
        this.IsAddNew=true;
    }
    HideAddNew():void{
        this.IsAddNew=false;
    }
}

You will see the following three things:

  1. All the employee related logical code is removed from AppComponent class to a new class called “EmployeeService
  2. Constructor of AppComponent class is no more the Default constructor. It’s changed into Parametrized constructor. It is accepting the parameter of type “EmployeeService”.
  3. You won’t see any code creating “EmployeeService” instance. At runtime, Angular creates the instance of EmployeeService class and pass it to the AppComponent constructor.

This is called “Dependency Injection” and hence “EmployeeService” is an injectable logic.

Step 4 – Test the Application

Just switch focus to the command window running TypeScript compiler and make sure that there is no compile error.

F5

Get into the browser and check the new output.

F6

Step 5 – Define the Provider

As I said before, Services need to be registered with Angular injector first. We haven’t done it yet.

It can be done either at Module level or at component level.

To register service, we need to register the provider. Provider provides the concrete, runtime version of the dependency value. Injector relies on providers to create instances of the services that the injector injects into other parts of the application.

In this lab, we will register Providers in Component level. Later in the future, we will move it to Module level and understand the difference and advantage both.

Open app.component.ts and modify “Component” decorator as follows:

JavaScript
import {EmployeeService} from "../Services/EmployeeService"
@Component({
selector:'app-component',
templateUrl:'./app.component.html',
providers:[{provide:EmployeeService,useClass:EmployeeService}]
})
export class AppComponent{

Check the providers section in the above code:

JavaScript
providers:[{provide:EmployeeService,useClass:EmployeeService}]

It means Angular injector will create instance of EmployeeService when other parts of the application ask for EmployeeService. It may seems illogical to you at this moment. “AppComponent is expecting EmployeeService and Angular Injector is creating and injecting EmployeeService”. What's the point when both expecting and injecting things are same? You will get to the answer very soon.

Step 6 – Check the Output

(Make sure your two command prompts are running. One with TypeScript compiler in watch mode and with lite-server.)

F7

Step 7 – Change the Dependency

Now it’s time to see the power of Dependency injection. Simply create one more TypeScript file “EmployeeDummyService.ts” in Services folder with the following content.

JavaScript
import {Employee} from "../Models/Employee"

export class EmployeeDummyService{
     Employees:Array<Employee>;
      constructor(){
        this.Employees =new Array<Employee>();
        
        let e1=new Employee();;
        e1.FName="Sukesh1";
        e1.LName="Marla1";
        e1.Salary=40000;
        this.Employees.push(e1);

        let e2=new Employee();;
        e2.FName="Gabbar2";
        e2.LName="Singh2";
        e2.Salary=50000;
        this.Employees.push(e2);
        
        let e3=new Employee();;
        e3.FName="Dragon3";
        e3.LName="Hunter4";
        e3.Salary=60000;
        this.Employees.push(e3);
    }
    GetEmployees():Array<Employee>{
        return this.GetEmployees();
    }
    SaveEmployee(e:Employee){
        this.Employees.push(e);
    }
}

As you can see, it has the same structure as “EmployeeService”, only data is different.

Now in “Component” decorator, change provider as follows:

JavaScript
import {Employee} from "../Models/Employee"
import {EmployeeService} from "../Services/EmployeeService"
import {EmployeeDummyService} from "../Services/EmployeeDummyService"
@Component({
selector:'app-component',
templateUrl:'./app.component.html',
providers:[{provide:EmployeeService,useClass:EmployeeDummyService}]
})
export class AppComponent{

It means Angular Injector creates instance of “EmployeeDummyService” and injects it when “EmployeeService” is expected.

Step 8 – Check the New Output

Switch to browser and check the new output.

F8

As you can see, now data is coming from newly created “EmployeeDumyyService”.

Now change provider back to EmployeeService and get project to original state.

As you can see, now my application logic is completely decoupled from the component.

What’s Next?

In Part 2 of Day 4, we will talk about input controls in detail.

License

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