Service

As we have discussed in Angular Architecture, Services are used for reusable data to share between components throughout an application.

Services are mainly used for HTTP Calls.

Components shouldn’t fetch or save data directly and they certainly shouldn’t knowingly present fake data. They should focus on presenting data and delegate data access to a service.

In the previous chapter, we have created two component,

ProductsComponent
ProductsComponent and
ProductComponent
ProductComponent. We are getting the dummy product list data from the
MockData
MockData class.

We have also written the code to remove

product
product in component. If we required this code in other component, we need to write it again.

It is not a good practice, to write business logic in component.

Instead of writing business logic code on component, we will move this common reusable code into Service class.

As shown below, we will create a separate class called

UserService
UserService, which will contain the reusable code and code to call the HTTP web service.

Methods written in service can be used by any component just by writing a dependency in that component constructor (dependency injection).

Services with Dependency Injection

We will create all services in a separate folder called

service
service. It is not a mandatory, but it is a good way to manage services and components separately.

Using terminal go into

service
service folder and execute below Angular CLI command.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
ng g service product
ng g service product
ng g service product

The command generates skeleton

ProductService
ProductService class in
src/app/service/product.service.ts.
src/app/service/product.service.ts. The ProductService class should look like the below.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
import { Injectable } from '@angular/core';
@Injectable()
export class ProductService {
constructor() { }
}
import { Injectable } from '@angular/core'; @Injectable() export class ProductService { constructor() { } }
import { Injectable } from '@angular/core';

@Injectable()
export class ProductService {

  constructor() { }

}

Notice that the new service imports the Angular Injectable symbol and annotates the class with the

@Injectable()
@Injectable() decorator.

The 

@Injectable()
@Injectable() decorator tells Angular that this service might itself have injected dependencies.

Service could get data from anywhere—a web service, local storage, or a mock data source.

Removing data access from components means you can change your mind about the implementation anytime, without touching any components. They don’t know how the service works.

The implementation in this tutorial will continue to deliver mock heroes.

We will update the ProductService as below, 

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
import { MockData } from './../mock-data/mock-product-data';
import { Injectable } from '@angular/core';
import { Product } from '../models/product';
@Injectable()
export class ProductService {
products: Product[] = [];
constructor() {
this.products = MockData.Products;
}
getProducts(): Product[] {
return this.products;
}
removeProduct(product: Product) {
let index = this.products.indexOf(product);
if (index !== -1) {
this.products.splice(index, 1);
}
}
}
import { MockData } from './../mock-data/mock-product-data'; import { Injectable } from '@angular/core'; import { Product } from '../models/product'; @Injectable() export class ProductService { products: Product[] = []; constructor() { this.products = MockData.Products; } getProducts(): Product[] { return this.products; } removeProduct(product: Product) { let index = this.products.indexOf(product); if (index !== -1) { this.products.splice(index, 1); } } }
import { MockData } from './../mock-data/mock-product-data';
import { Injectable } from '@angular/core';
import { Product } from '../models/product';

@Injectable()
export class ProductService {

  products: Product[] = [];
  constructor() {
    this.products = MockData.Products;
  }

  getProducts(): Product[] {
    return this.products;
  }

  removeProduct(product: Product) {
    let index = this.products.indexOf(product);
    if (index !== -1) {
      this.products.splice(index, 1);
    }
  }
}

We must provide the ProductService in the dependency injection system before Angular can inject it into the ProductsComponent and ProductComponent, as we will do below.

There are several ways to provide the ProductService: in the ProductsComponent, in the AppComponent, in the AppModule. Each option has pros and cons.

In this tutorial, we will provide ProductService in AppModule.

That’s such a popular choice that we could have told the CLI to provide it there automatically by appending 

--module=app
--module=app.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
ng g service product --module=app
ng g service product --module=app
ng g service product --module=app

Since we did not, we will have to provide it manually.

Open the 

AppModule
AppModule class, import the 
ProductService
ProductService, and add it to the 
@NgModule.providers
@NgModule.providers array.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
import { ProductService } from './service/product.service';
@NgModule({
...
providers: [ProductService],
...
})
export class AppModule { }
import { ProductService } from './service/product.service'; @NgModule({ ... providers: [ProductService], ... }) export class AppModule { }
import { ProductService } from './service/product.service';
@NgModule({
        ...
  	providers: [ProductService],
  	...	
})
export class AppModule { }

The providers array tells Angular to create a single, shared instance of 

ProductService
ProductService and inject into any class that asks for it.

The 

ProductService
ProductService is now ready to plug into the 
ProductsComponent
ProductsComponent and
ProductComponent
ProductComponent.

Update ProductsComponent as below, Delete the MockData import as we won’t need that anymore.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
import { ProductService } from './../service/product.service';
import { Component, OnInit } from '@angular/core';
import { Product } from '../models/product';
@Component({
selector: 'app-products',
templateUrl: './products.component.html',
styleUrls: ['./products.component.css']
})
export class ProductsComponent implements OnInit {
products: Product[] = [];
constructor(public productService: ProductService) {
this.products = productService.getProducts();
}
ngOnInit() {
}
deleteProduct(product: Product) {
this.productService.removeProduct(product);
this.products = this.productService.getProducts();
}
}
import { ProductService } from './../service/product.service'; import { Component, OnInit } from '@angular/core'; import { Product } from '../models/product'; @Component({ selector: 'app-products', templateUrl: './products.component.html', styleUrls: ['./products.component.css'] }) export class ProductsComponent implements OnInit { products: Product[] = []; constructor(public productService: ProductService) { this.products = productService.getProducts(); } ngOnInit() { } deleteProduct(product: Product) { this.productService.removeProduct(product); this.products = this.productService.getProducts(); } }
import { ProductService } from './../service/product.service';
import { Component, OnInit } from '@angular/core';
import { Product } from '../models/product';

@Component({
  selector: 'app-products',
  templateUrl: './products.component.html',
  styleUrls: ['./products.component.css']
})
export class ProductsComponent implements OnInit {

  products: Product[] = [];

  constructor(public productService: ProductService) {
    this.products = productService.getProducts();
  }

  ngOnInit() {
  }

  deleteProduct(product: Product) {
    this.productService.removeProduct(product);

    this.products = this.productService.getProducts();
  }

}

as shown above, we have injected

ProductService
ProductService using a constructor. 

Now, we can use the

ProductService
ProductService methods into
ProductsComponent
ProductsComponent. we have used the getProducts() and removeProduct() method.

If you will not provide the ProductService in containing module or in that component. it will generate an error as below : 

As you can see in the error, a component is not able to find the provider of

ProductService
ProductService. Because we have not provided ProductService in the provider property of @NgModule metadata.

To resolve this error, add ProductService in the provider array of containing module, here containing module is AppModule.

product.service.ts
app.module.ts
products.component.ts
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
import { MockData } from './../mock-data/mock-product-data';
import { Injectable } from '@angular/core';
import { Product } from '../models/product';
@Injectable()
export class ProductService {
products: Product[] = [];
constructor() {
this.products = MockData.Products;
}
getProducts(): Product[] {
return this.products;
}
removeProduct(product: Product) {
let index = this.products.indexOf(product);
if (index !== -1) {
this.products.splice(index, 1);
}
}
}
import { MockData } from './../mock-data/mock-product-data'; import { Injectable } from '@angular/core'; import { Product } from '../models/product'; @Injectable() export class ProductService { products: Product[] = []; constructor() { this.products = MockData.Products; } getProducts(): Product[] { return this.products; } removeProduct(product: Product) { let index = this.products.indexOf(product); if (index !== -1) { this.products.splice(index, 1); } } }
import { ProductService } from './service/product.service';
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { ProductsComponent } from './products/products.component';
import { ProductComponent } from './product/product.component';
@NgModule({
declarations: [
AppComponent,
ProductsComponent,
ProductComponent
],
imports: [
BrowserModule
],
providers: [ProductService],
bootstrap: [AppComponent]
})
export class AppModule { }
import { ProductService } from './service/product.service'; import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { AppComponent } from './app.component'; import { ProductsComponent } from './products/products.component'; import { ProductComponent } from './product/product.component'; @NgModule({ declarations: [ AppComponent, ProductsComponent, ProductComponent ], imports: [ BrowserModule ], providers: [ProductService], bootstrap: [AppComponent] }) export class AppModule { }
import { ProductService } from './../service/product.service';
import { Component, OnInit } from '@angular/core';
import { Product } from '../models/product';
@Component({
selector: 'app-products',
templateUrl: './products.component.html',
styleUrls: ['./products.component.css']
})
export class ProductsComponent implements OnInit {
products: Product[] = [];
constructor(public productService: ProductService) {
this.products = productService.getProducts();
}
ngOnInit() {
}
deleteProduct(product: Product) {
this.productService.removeProduct(product);
this.products = this.productService.getProducts();
}
}
import { ProductService } from './../service/product.service'; import { Component, OnInit } from '@angular/core'; import { Product } from '../models/product'; @Component({ selector: 'app-products', templateUrl: './products.component.html', styleUrls: ['./products.component.css'] }) export class ProductsComponent implements OnInit { products: Product[] = []; constructor(public productService: ProductService) { this.products = productService.getProducts(); } ngOnInit() { } deleteProduct(product: Product) { this.productService.removeProduct(product); this.products = this.productService.getProducts(); } }
import { MockData } from './../mock-data/mock-product-data';
import { Injectable } from '@angular/core';
import { Product } from '../models/product';

@Injectable()
export class ProductService {

  products: Product[] = [];
  constructor() {
    this.products = MockData.Products;
  }

  getProducts(): Product[] {
    return this.products;
  }

  removeProduct(product: Product) {
    let index = this.products.indexOf(product);
    if (index !== -1) {
      this.products.splice(index, 1);
    }
  }
}
import { ProductService } from './service/product.service';
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { ProductsComponent } from './products/products.component';
import { ProductComponent } from './product/product.component';

@NgModule({
  declarations: [
    AppComponent,
    ProductsComponent,
    ProductComponent
  ],
  imports: [
    BrowserModule
  ],
  providers: [ProductService],
  bootstrap: [AppComponent]
})
export class AppModule { }
import { ProductService } from './../service/product.service';
import { Component, OnInit } from '@angular/core';
import { Product } from '../models/product';

@Component({
  selector: 'app-products',
  templateUrl: './products.component.html',
  styleUrls: ['./products.component.css']
})
export class ProductsComponent implements OnInit {

  products: Product[] = [];

  constructor(public productService: ProductService) {
    this.products = productService.getProducts();
  }

  ngOnInit() {
  }

  deleteProduct(product: Product) {
    this.productService.removeProduct(product);

    this.products = this.productService.getProducts();
  }

}
  • We have seen the purpose of Service.
  • We have created
    ProductService
    ProductService, in that service we have created
    getProducts()
    getProducts() and
    removeProduct()
    removeProduct() method.
  • After that, we have provided
    ProductService
    ProductService in
    AppModule
    AppModule.
  • We have injected the
    ProductService
    ProductService in
    ProductsComponent
    ProductsComponent.
  • At the end, we have consumed the
    ProductService
    ProductService methods in
    ProductsComponent
    ProductsComponent.