In Angular, services are classes that provide specific functionality that can be used across multiple components. They allow you to centralize logic, share data between components, and manage external interactions, such as with databases or APIs.

We can reuse the method, which is a duplicate, and the DRY principle is automatically applied here.

Key Points:

  • Services allow for data sharing across components.
  • They encapsulate business logic and application logic.
  • Angular services are typically used with Dependency Injection (DI), allowing you to inject services into components.
  • Services can be injected globally or locally into components.
  • To create a service ng generate service my-service --skip-tests

Naming Convention for Service:

It is common to name services with the service suffix, e.g., mathGenerate.service.ts.


Example 1: Service with Dependency Injection (DI)

1. Service (with DI)

In this example, we define a service that provides a method for getting data. This service is injected into a component.

data.service.ts:

import { Injectable } from '@angular/core';
 
@Injectable({
  providedIn: 'root'  // This ensures the service is available globally across the application
})
export class DataService {
  getData(): string {
    return 'Hello from DataService';
  }
}
  • @Injectable() decorator: This marks the class as a service that can be injected.
  • providedIn: 'root': This tells Angular to provide the service globally.

2. Component Using the Service

Now, in the component, we inject the DataService via its constructor and use it.

app.component.ts:

import { Component } from '@angular/core';
import { DataService } from './data.service';  // Import the service
 
@Component({
  selector: 'app-root',
  template: `<h1>{{ data }}</h1>`  // Display the data in the template
})
export class AppComponent {
  data: string;
 
  // Injecting the service into the constructor
  constructor(private dataService: DataService) {
    this.data = dataService.getData();  // Using the injected service to get data
  }
}
  • The DataService is injected into the component via the constructor.
  • this.data = dataService.getData() uses the service to get data and displays it.

Example 2: Without Dependency Injection (Manual Instantiation)

In this example, the service is manually instantiated in the component, rather than using Angular’s DI system. This is not considered a good practice.

1. Service (Manual Instantiation)

data.service.ts:

export class DataService {
  getData(): string {
    return 'Hello from DataService';
  }
}
  • The service class is similar, but there is no @Injectable() decorator, and it is not provided globally.

2. Component Manually Instantiating the Service

app.component.ts:

import { Component } from '@angular/core';
import { DataService } from './data.service';  // Import the service
 
@Component({
  selector: 'app-root',
  template: `<h1>{{ data }}</h1>`  // Display the data in the template
})
export class AppComponent {
  data: string;
  dataService: DataService;
 
  // Manually creating the instance of the service
  constructor() {
    this.dataService = new DataService();  // Creating the service instance manually
    this.data = this.dataService.getData();  // Using the manually created service to get data
  }
}
  • Manual instantiation: Instead of relying on DI, we create an instance of the service manually using new DataService().
  • This approach is not as clean as DI and is not scalable in larger applications. DI allows better flexibility and testability.

Comparison: DI vs Manual Instantiation

  • With DI:
    • The service is automatically provided and injected into the component, ensuring cleaner, more scalable, and testable code.
    • No manual instance creation in components.
    • The service is shared across multiple components, and Angular manages the lifecycle.
  • Without DI (Manual Instantiation):
    • The component is responsible for creating an instance of the service using new.
    • This is less flexible and harder to manage, especially when the application grows.
    • No centralized management of service lifecycle.

When to Use DI:

  • When you need to share data or logic across multiple components.
  • For external interactions, such as fetching data from an API or connecting to a database.
  • For better testability and scalability in larger applications.

Summary:

  • Services are classes used to provide functionality or share data across components.
  • Services are usually implemented using Dependency Injection (DI), which allows Angular to inject services into components automatically.
  • Manual instantiation can be used, but it is not recommended for large-scale applications due to its limitations. DI simplifies managing services and promotes cleaner code.