Swiftorial Logo
Home
Swift Lessons
Matchups
CodeSnaps
Tutorials
Career
Resources

Dependency Injection in Angular

Dependency Injection (DI) is a design pattern used to implement IoC (Inversion of Control), allowing the creation of dependent objects outside of a class and providing those objects to a class in various ways. This tutorial provides an overview of dependency injection in Angular, its key features, and how to use it effectively.

What is Dependency Injection?

Dependency Injection is a pattern that allows a class to receive its dependencies from an external source rather than creating them itself. In Angular, DI is used to provide components and services with the necessary dependencies, promoting modularity, testability, and maintainability.

Key Features of Dependency Injection in Angular

Angular's dependency injection system provides several key features:

  • Providers: Define how to create an instance of a dependency.
  • Injectors: Maintain a registry of providers and create instances of dependencies as needed.
  • Tokens: Identify the type of dependency to be injected.
  • Hierarchical Injectors: Allow different injectors to manage their own sets of providers, enabling different parts of the application to use different dependencies.

Creating a Service with Dependency Injection

To demonstrate DI in Angular, let's create a simple service and inject it into a component.

Step 1: Create a Service

First, generate a new service using Angular CLI:

ng generate service my-service

This command creates a new service file. Here's an example of a simple service:

import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class MyService {
  getValue(): string {
    return 'Hello from MyService!';
  }
}

Step 2: Inject the Service into a Component

Next, inject the service into a component:

import { Component, OnInit } from '@angular/core';
import { MyService } from './my-service.service';

@Component({
  selector: 'app-my-component',
  template: '<p>{{ value }}</p>'
})
export class MyComponent implements OnInit {
  value: string;

  constructor(private myService: MyService) {}

  ngOnInit(): void {
    this.value = this.myService.getValue();
  }
}

The MyService is injected into the component through the constructor. The service's getValue method is called in the ngOnInit lifecycle hook, and the returned value is assigned to the value property.

Providing Services

Services can be provided at different levels:

  • Root Level: Services provided at the root level are available throughout the application. This is the default when you use the @Injectable decorator with providedIn: 'root'.
  • Module Level: Services can be provided in a specific module by adding them to the providers array of the module's metadata.
  • Component Level: Services can be provided in a specific component by adding them to the providers array of the component's metadata. This creates a new instance of the service for that component and its children.

Injection Tokens

Injection tokens are used to uniquely identify dependencies. Angular provides several built-in tokens, but you can also create custom tokens. Here's an example of creating and using a custom injection token:

import { InjectionToken } from '@angular/core';

export const MY_TOKEN = new InjectionToken<string>('MyToken');

// Providing the token
@NgModule({
  providers: [
    { provide: MY_TOKEN, useValue: 'Hello from custom token!' }
  ]
})
export class AppModule {}

// Injecting the token
@Component({
  selector: 'app-token-component',
  template: '<p>{{ tokenValue }}</p>'
})
export class TokenComponent {
  constructor(@Inject(MY_TOKEN) public tokenValue: string) {}
}

Conclusion

Dependency Injection is a powerful pattern in Angular that promotes modularity, testability, and maintainability. By understanding and using providers, injectors, and tokens effectively, you can build robust and scalable Angular applications. Happy coding!