
Dependency Injection (DI) is a core concept in Angular that allows for better organization, management, and testing of your code. In this blog post, we'll explore what DI is, how it works in Angular, and provide practical examples to help you implement it in your projects.
Dependency Injection is a design pattern used to implement Inversion of Control (IoC) between classes and their dependencies. Instead of creating dependencies manually, they are injected into a class, making the class more modular, testable, and maintainable.
Angular provides a built-in dependency injection framework. Here's a breakdown of how it works:
Let's go through a simple example to understand how to set up and use dependency injection in an Angular application.
First, we'll create a service that we want to inject into our components.
typescript
Copy code
// src/app/services/logger.service.ts
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root',
})
export class LoggerService {
log(message: string): void {
console.log(`LoggerService: ${message}`);
}
}
In this example, the LoggerService is decorated with @Injectable, and it's provided in the root injector, making it available application-wide.
Next, we'll inject the LoggerService into a component.
typescript
Copy code
// src/app/components/example/example.component.ts
import { Component, OnInit } from '@angular/core';
import { LoggerService } from '../../services/logger.service';
@Component({
selector: 'app-example',
templateUrl: './example.component.html',
styleUrls: ['./example.component.css'],
})
export class ExampleComponent implements OnInit {
constructor(private logger: LoggerService) {}
ngOnInit(): void {
this.logger.log('ExampleComponent initialized');
}
}
Here, the LoggerService is injected into the ExampleComponent via the constructor. The logger instance can then be used within the component.
Finally, you can use the injected service in your component's logic.
typescript
Copy code
// src/app/components/example/example.component.ts
export class ExampleComponent implements OnInit {
constructor(private logger: LoggerService) {}
ngOnInit(): void {
this.logger.log('ExampleComponent initialized');
}
someMethod(): void {
this.logger.log('someMethod called');
}
}
You can also provide services at the module level. This is useful when you want to limit the scope of a service to a specific feature module.
typescript
Copy code
// src/app/feature/feature.module.ts
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FeatureComponent } from './feature.component';
import { FeatureService } from './feature.service';
@NgModule({
declarations: [FeatureComponent],
imports: [CommonModule],
providers: [FeatureService],
})
export class FeatureModule {}
For more complex scenarios, such as injecting configuration objects, you can use InjectionToken.
typescript
Copy code
// src/app/app.module.ts
import { NgModule, InjectionToken } from '@angular/core';
export const APP_CONFIG = new InjectionToken<AppConfig>('app.config');
export interface AppConfig {
apiEndpoint: string;
}
const config: AppConfig = {
apiEndpoint: 'https://api.example.com',
};
@NgModule({
providers: [{ provide: APP_CONFIG, useValue: config }],
})
export class AppModule {}
Dependency Injection is a powerful feature in Angular that promotes better code organization, maintainability, and testability. By understanding and leveraging DI, you can create more modular and scalable applications. We hope this guide has provided you with a clear understanding of how DI works in Angular and how to implement it in your projects.