Finally completed Day 3.
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
- Day 1 – Part 1
- Day 1 – Part 2
- Day 2
- Day 3
- Day 4 – Part 1
- Day 4 – Execution trick
- Day 4 – Part 2
- Day 4 – Part 3
- Day 5 (Coming soon)
- Day 6 (Coming soon)
- Day 7 (Coming soon)
- Day 8 (Coming soon)
- Day 9 (Coming soon)
- 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 a practical demonstration, it will be much clearer.)
All major technologies have support for implementing DI now a days. These technologies and frameworks have something called an “injector”. Injector at run time creates instance of dependency and makes it available to the application.
The 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 makes 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 put it 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:
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:
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:
- All the
employee
related logical code is removed from AppComponent
class to a new class called “EmployeeService
”. - Constructor of
AppComponent
class is no more the Default constructor. It’s changed into Parametrized constructor. It is accepting the parameter of type “EmployeeService
”. - 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.
Get into the browser and check the new output.
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 both the difference and advantage.
Open app.component.ts and modify “Component
” decorator as follows:
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.
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 seem illogical to you at this moment. “AppComponent
is expecting EmployeeService
and Angular Injector is creating and injecting EmployeeService
”. What 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.)
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:
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.Employees;
}
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:
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.
As you can see, now data is coming from newly created “EmployeeDumyyService
”.
Now change provider back to EmployeeService
and get project to the original state.
As you can see, now my application logic is completely decoupled from the component.
Summary
In case of any queries, you can drop a comment. I will try my best to reply at the earliest.
CodeProject