Why Dependency Injection?
Loose Coupling
Components don’t need to know how to create dependencies
Testability
Easy to provide mock dependencies for testing
Reusability
Services can be shared across components
Maintainability
Change implementations without modifying consumers
The @Injectable Decorator
Mark a class as available for injection:providedIn: 'root' makes the service available throughout the application as a singleton.Provider Scopes
Angular supports several scopes for providing services:Root Scope
Application-wide singleton:Component Scope
Provide a service at the component level:Platform Scope
Shared across multiple Angular applications on the same page:Using inject() Function
The modern way to inject dependencies:Constructor Injection (Legacy)
Traditional approach using constructor parameters:Injection Tokens
Provide non-class dependencies:Provider Types
Angular supports several provider configurations:Class Provider
Value Provider
Factory Provider
Existing Provider
Alias one token to another:Optional Dependencies
Handle missing dependencies gracefully:Self and SkipSelf
Control dependency resolution:Hierarchical Injection
Angular creates a hierarchy of injectors:1
Platform Injector
Shared across all applications on the page
2
Root Injector
Application-wide services (providedIn: ‘root’)
3
Module Injectors
Created for lazy-loaded modules (legacy)
4
Component Injectors
Created when components have providers
5
Element Injectors
Created for directives with providers
Best Practices
- Use inject() over constructor injection for modern applications
- Provide in root for application-wide singletons
- Use component providers for component-specific state
- Leverage injection tokens for configuration and non-class dependencies
- Keep services focused on single responsibilities
- Avoid circular dependencies between services
- Use factory providers for complex initialization logic
Next Steps
Services
Learn to create and use services
Components
Understand component architecture
