Angular Service (Day 8)
In this article, we will discuss the concept of Service in Angular 8. Angular service plays an important role to communicate with the backend layer of any application from the component level to send or retrieve data. That’s why Service is another backbone of any angular application. So, it is very important to understand why it is required and how to use it in any applications?
What is Angular Service?
- Create a class with @Injectable decorator.
- Register the class with the provider or inject the class by using dependency injection.
Benefits of using Service
How to define a Service
We can create a user-defined custom service as per our requirement. To create a service, we need to follow the below steps:
- First, we need to create a TypeScript file with proper naming.
- Next, create a TypeScript class with the proper name that will represent the service after a while.
- Use the @Injectable decorator at the beginning of the class name that was imported from the @angular/core packages. Basically, the purpose of the @Injectable is that user-defined service and any of its dependents can be automatically injected by the other components.
- Although, for design readability, Angular recommends that you always define the @Injectable decorator whenever you create any service.
- Now, use the Export keyword against the class objects so that this service can be injectable or reused on any other components.
NOTE
When we create our custom service available to the whole application through the use of a provider’s metadata, this provider’s metadata must be defined in the app.module.ts(main application module file) file. If you provide the service in the main module file, then it is visible to the whole application. If you provide it in any component, then only that component can use the service. By providing the service at the module level, Angular creates only one instance of the CustomService class, which can be used by all the components in an application.
- import { Injectable } from '@angular/core';
- @Injectable()
- export class AlertService
- {
- constructor()
- { }
- publish showAlert(message: string)
- {
- alert(message);
- }
- }
@Injectable()
Most important is that any class needs to define with @Injectable() decorator so that it can be injected into the application.
- @Injectable()
- export class SampleService
- {
- constructor()
- {
- console.log('Sample service is created');
- }
- }
What is Dependency Injection?
- Internal cache
In Angular, every dependency object created as a singleton object. So, when we inject any service class as a dependent object, then the instance of that service class created once for the entire application lifecycle. - Namespace collision
In Angular, we can’t be injected two different service classes from two different modules with the same name. As an example, suppose we create a service called user service for our own module and we inject that service. Now, suppose we import an EmployeeModule which contains the same name service called UserService and we also want to inject that. Then that can’t be done since the same name service already injected in the application. - Built into the framework
In Angular Framework, Dependency Injection is totally tightly coupled with Angular Modules. We can’t decouple the Dependency Injection from the Angular module as a standalone system.
In Angular Framework, Dependency Injection contains three sections like Injector, Provider & Dependency.
- Injector
The main purpose of the using Injector section is the expose an object or APIs which basically helps us to create instances of the dependent class or services. - Provider
A Provider is basically acting as an Instructor or Commander. It basically provides instruction to the injector about the process of creating instances of the dependent objects. The provider always taken the token value as input and then map that token value with the newly created instances of the class objects. - Dependency
Dependency is the processor type that basically identifies the nature of the created objects.
So as per the above discussion, we can perform the below tasks using the Dependency Injection in Angular Framework,
- We can create instances of the service classes in the constructor level using the provider metadata.
- We can use providers to resolve the dependencies between module-level providers and component level providers.
- The dependency injection process creates the instances of the dependent class and provides the reference of those objects when we required in the code.
- All the instances of the dependency injected objects are created as a Singletone object.
What is Provider?
- A class provider always generates or provides an instance of a class
- A factory provider generates or provides whatever returns when we run a specified function
- A value provider does not need to take up action to provide the result, it just returns a value
Sample of a Class
- export class testClass {
- public message: string = "Hello from Service Class";
- public count: number;
- constructor() {
- this.count=1;
- }
- }
- Import testClass
- Add it to the @Component() decorator property
- import { Component } from "@angular/core";
- import { testClass} from "./service/testClass";
- @Component({
- module : module.id,
- selector : ‘test-prog’,
- template : ‘<h1>Hello {{_message}}</h1>’,
- providers : [testClass]
- })
- export class TestComponent
- {
- private _message:string="";
- constructor(private _testClass : testClass)
- {
- this._message = this._testClass.message;
- }
- }
Inject a Service into a Module
- @NgModule({
- imports: [ BrowserModule, FormsModule ],
- declarations: [ AppComponent, ParentComponent, ChildComponent ],
- bootstrap: [ AppComponent ],
- providers: [ SimpleService, EmailService ] ①
- })
- class AppModule { }
Inject a Service into a Component
We can also inject the Angular Service into the Component Level. Similarly like NgModule, providers' property of Component decorator gives us the ability to inject a list number of Angular services within that particular component. It will provide a single instance of the Angular Service across the entire component along with the child component.
- @Component({
- selector: 'parent',
- template: `...`,
- providers: [ EmailService ]
- })
- class ParentComponent {
- constructor(private service: EmailService) { }
- }
Demo 1 - Basic Service
- import { Component, OnInit } from '@angular/core';
- import { StudentService } from './app.service';
- @Component({
- selector: 'app-root',
- templateUrl: './app.component.html',
- styleUrls : ['./custom.css']
- })
- export class AppComponent implements OnInit {
- private _model: any = {};
- private _source: Array<any>;
- constructor(private _service: StudentService) {
- this._source = this._service.returnStudentData();
- }
- ngOnInit(): void {
- }
- private submit(): void {
- if (this.validate()) {
- this._service.addStudentData(this._model);
- this.reset();
- }
- }
- private reset(): void {
- this._model = {};
- }
- private validate(): boolean {
- let status: boolean = true;
- if (typeof (this._model.name) === "undefined") {
- alert('Name is Blank');
- status = false;
- return;
- }
- else if (typeof (this._model.age) === "undefined") {
- alert('Age is Blank');
- status = false;
- return;
- }
- else if (typeof (this._model.city) === "undefined") {
- alert('City is Blank');
- status = false;
- return;
- }
- else if (typeof (this._model.dob) === "undefined") {
- alert('dob is Blank');
- status = false;
- return;
- }
- return status;
- }
- }
app.component.html
- <div style="padding-left: 20px">
- <h2>Student Form</h2>
- <table style="width:80%;">
- <tr>
- <td>Student Name</td>
- <td><input type="text" [(ngModel)]="_model.name" /></td>
- </tr>
- <tr>
- <td>Age</td>
- <td><input type="number" [(ngModel)]="_model.age" /></td>
- </tr>
- <tr>
- <td>City</td>
- <td><input type="text" [(ngModel)]="_model.city" /></td>
- </tr>
- <tr>
- <td>Student DOB</td>
- <td><input type="date" [(ngModel)]="_model.dob" /></td>
- </tr>
- <tr>
- <td></td>
- <td>
- <input type="button" value="Submit" (click)="submit()" />
- <input type="button" value="Reset" (click)="reset()" />
- </td>
- </tr>
- </table>
- <h3>Student Details</h3>
- <div class="ibox-content">
- <div class="ibox-table">
- <div class="table-responsive">
- <table class="responsive-table table-striped table-bordered table-hover">
- <thead>
- <tr>
- <th style="width:40%;">
- <span>Student's Name</span>
- </th>
- <th style="width:15%;">
- <span>Age</span>
- </th>
- <th style="width:25%;">
- <span>City</span>
- </th>
- <th style="width:20%;">
- <span>Date of Birth</span>
- </th>
- </tr>
- </thead>
- <tbody>
- <tr *ngFor="let item of _source; let i=index">
- <td><span>{{item.name}}</span></td>
- <td><span>{{item.age}}</span></td>
- <td><span>{{item.city}}</span></td>
- <td><span>{{item.dob}}</span></td>
- </tr>
- </tbody>
- </table>
- </div>
- </div>
- </div>
- </div>
app.service.ts
- import { Injectable } from "@angular/core";
- @Injectable()
- export class StudentService {
- private _studentList: Array<any> = [];
- constructor() {
- this._studentList = [{name:'Amit Roy', age:20, city:'Kolkata', dob:'01-01-1997'}];
- }
- returnStudentData(): Array<any> {
- return this._studentList;
- }
- addStudentData(item: any): void {
- this._studentList.push(item);
- }
- }
app.module.ts
- import { BrowserModule } from '@angular/platform-browser';
- import { NgModule, NO_ERRORS_SCHEMA } from '@angular/core';
- import { FormsModule, ReactiveFormsModule } from '@angular/forms';
- import { AppComponent } from './app.component';
- import { StudentService } from './app.service';
- @NgModule({
- declarations: [
- AppComponent
- ],
- imports: [
- BrowserModule, FormsModule, ReactiveFormsModule
- ],
- providers: [StudentService],
- bootstrap: [AppComponent],
- schemas: [NO_ERRORS_SCHEMA]
- })
- export class AppModule { }
Now check the browser for the output,
Demo 2 - Inject Service into a Module
parent.component.ts
- import { Component, OnInit } from '@angular/core';
- import { DemoService } from './app.service';
- @Component({
- selector: 'parent',
- templateUrl: './parent.component.html',
- styleUrls : ['./custom.css']
- })
- export class ParentComponent implements OnInit {
- constructor(private demoService:DemoService){
- }
- ngOnInit(){
- }
- }
parent.component.html
- <div class="parent">
- <p>Parent Component</p>
- <div class="form-group">
- <input type="text" class="form-control" name="value" [(ngModel)]="demoService.message">
- </div>
- <child></child>
- </div>
child.component.ts
- import { Component, OnInit } from '@angular/core';
- import { DemoService } from './app.service';
- @Component({
- selector: 'child',
- templateUrl: './child.component.html',
- styleUrls : ['./custom.css']
- })
- export class ChildComponent implements OnInit {
- constructor(private demoService:DemoService){
- }
- ngOnInit(){
- }
- }
child.component.html
- <div class="child">
- <p>Child Component</p>
- {{ demoService.message }}
- </div>
app.component.ts
- import { Component, OnInit } from '@angular/core';
- @Component({
- selector: 'app-root',
- templateUrl: './app.component.html',
- styleUrls : ['./custom.css']
- })
- export class AppComponent implements OnInit {
- ngOnInit(){
- }
- }
app.component.html
- <div style="padding-left: 20px;padding-top: 20px; width: 500px;">
- <div class="row">
- <div class="col-xs-6">
- <h2>Parent Componet - 1</h2>
- <parent></parent>
- </div>
- <div class="col-xs-6">
- <h2>Parent Componet - 2</h2>
- <parent></parent>
- </div>
- </div>
- </div>
custom.css
- .parent{
- background-color: bisque;
- font-family: Arial, Helvetica, sans-serif;
- font-weight: bolder;
- font-size: large;
- }
- .child{
- background-color:coral;
- font-family: Georgia, 'Times New Roman', Times, serif;
- font-weight: bold;
- font-size: medium;
- }
app.module.ts
- import { BrowserModule } from '@angular/platform-browser';
- import { NgModule, NO_ERRORS_SCHEMA } from '@angular/core';
- import { FormsModule, ReactiveFormsModule } from '@angular/forms';
- import { AppComponent } from './app.component';
- import { ParentComponent } from './parent.component';
- import { ChildComponent } from './child.component';
- import { DemoService } from './app.service';
- @NgModule({
- declarations: [
- AppComponent,ParentComponent,ChildComponent
- ],
- imports: [
- BrowserModule, FormsModule, ReactiveFormsModule
- ],
- providers: [DemoService],
- bootstrap: [AppComponent],
- schemas: [NO_ERRORS_SCHEMA]
- })
- export class AppModule { }
Now check the output into the browser,In the above example, we see that if we input some text in any one parent component input box, it will automatically update the related nested child component along with another parent component also. This is occurred because of the DemoService is injected into the Module level. So it creates a single-tone instance of that service and that instance is available across the entire application.
Demo 3 - Inject Service into a Component
- import { Component, OnInit } from '@angular/core';
- import { DemoService } from './app.service';
- @Component({
- selector: 'parent',
- templateUrl: './parent.component.html',
- styleUrls : ['./custom.css'],
- providers:[DemoService]
- })
- export class ParentComponent implements OnInit {
- constructor(private demoService:DemoService){
- }
- ngOnInit(){
- }
- }
Conclusion
In this article, we discussed another important feature of Angular Framework i.e. Angular Service. Also, we discussed the basic concept of Angular along with its benefit and how to use it in an Angular Application. Now, in the next article, we will how to handle the ajax request in an Angular Application.