21. Understanding Dependency Injection (DI)
Dependency Injection (DI) is a core design pattern in Angular. It allows a class (the dependent) to receive its dependencies (other objects it needs to perform its function) from an external source, rather than creating them itself.
Why Use DI?
- Reusability: Services can be reused across different components.
- Testability: Easier to swap real dependencies with mock implementations during testing.
- Maintainability: Decouples components from their dependencies, reducing complexity.
The Three Parts of DI
- The Consumer/Dependent: The component or service that needs the dependency (e.g., a
ProductComponentneeds aProductService). - The Dependency: The class that provides the required functionality (e.g.,
ProductService). - The Injector: Angular's built-in mechanism that creates and manages the dependency instances and injects them into the consumer.
How Angular Handles Injection
Angular's Injector maintains a map of tokens (usually the class type) to providers (recipes for creating the instance).
When a component requests a dependency via its constructor, Angular looks for a matching provider in its injection tree (starting at the component level and moving up to the module, and finally the root).
Example of requesting a dependency:
typescript import { LoggerService } from './logger.service';
// Angular reads the constructor parameter and tries to fulfill the dependency export class MyComponent { constructor(private logger: LoggerService) { // The logger instance is provided by Angular's injector this.logger.log('Component initialized.'); } }