Dependency Injection (DI) is a core feature of Angular, enabling the inversion of control by supplying a class with its required dependencies rather than instantiating them internally. This design pattern fosters loose coupling and simplifies testing by decoupling dependencies from the class logic.
Beyond being a programming technique, DI embodies a design philosophy emphasizing modularity, flexibility, and testability in application development. In Angular, DI enhances code readability, streamlines dependency management, and allows for greater adaptability when modifying applications.
Injector in Angular
An injector is an abstraction responsible for storing and resolving instances of required dependencies. They are defined on several levels and organized in a hierarchy:
- Element Injector - registers dependencies at the component/directive level. Each component instance gets its own instance of dependency, which is also available to its descendants.
- Environment Injector - child hierarchies of the environment injector are created whenever dynamically loaded components are created, such as with a route.
- Environment Root Injector - contains globally available singleton dependencies
- Platform Injector - registers platform-specific dependencies
- Null Injector - the highest injector in the hierarchy. It throws an error if the dependency hasn’t been found

Resolution modifiers
The described resolution path may be affected by defining modifiers like:
- Optional - if the dependency hasn’t been found, Angular returns null instead of throwing an error.
- Self - makes Angular look for the dependency only in the element injector of the component.
- Skip Self - Angular starts looking for dependency from the Element Injector of the parent component.
- Host - restricts the dependency lookup to the host of the element.
Dependency Provider
A dependency provider is a recipe that tells Angular how to create an instance of dependency.
- Class provider - creates and resolves new instance of defined class replacing class defined as a token
- Alias provider - maps one token to another without creating a new instance but resolving the existing one
- Factory provider - resolves a dependency based on runtime values by calling a factory function
- Value provider - associate a static value with the token
Injection Token
Injection Tokens are used to uniquely identify dependencies in situations where their types are ambiguous, such as when multiple services share the same type or when injecting non-class dependencies like strings or objects. By providing a unique identifier, Injection Tokens ensure Angular can correctly resolve and inject the desired dependency, thereby maintaining flexibility and avoiding naming conflicts in the DI system.
Read the full article here! - Dependency Injection in Angular – everything you need to know
