Chapter 5.2โ˜• 15 min read

Dependency Injection โ€” How Angular Resolves

Angular gives you dependencies โ€” you don't create them yourself.

01What is Dependency Injection

Dependency Injection (DI) is a pattern where Angular provides dependencies to your classes instead of you creating them.

"DI = Swiggy delivery โ€” tum biryani nahi banate, Swiggy deliver karta hai."

Without DI: You create everything yourself:

const logger = new LoggerService();\nconst http = new HttpClient();\nconst router = new Router();\n// You manage creation, lifecycle, cleanup...

With DI: You ask, Angular provides:

private logger = inject(LoggerService);\nprivate http = inject(HttpClient);

Angular creates, manages, and provides the instances โ€” you just use them.

02The Injector โ€” Angular's Delivery System

The Injector is the core of DI โ€” it's a container that holds service instances and knows how to create them.

"Injector = warehouse โ€” order do, milega."

When you call inject(ServiceName), Angular:

  1. Checks the injector if an instance already exists
  2. If yes โ†’ returns that instance
  3. If no โ†’ creates a new instance using the provider, stores it, and returns it

Angular doesn't have ONE injector โ€” it has a tree of injectors that mirrors your component tree.

03Injector Hierarchy โ€” Tree of Injectors

Angular's injectors are organized in a hierarchy:

  • Root injector (AppModule/app.config level) โ€” topmost, one per app
  • Component injector โ€” each component has its own injector

"Root injector = Hyderabad main warehouse, Component injector = local branch."

When a component asks for a service, Angular:

  1. Checks the component's own injector first
  2. If not found, checks the parent component's injector
  3. Keeps going up the tree until it reaches the root injector
  4. If still not found โ†’ throws an error

This is why providedIn: 'root' makes a service available everywhere โ€” it lives in the root injector that ALL components can reach.

04Resolution Process Step by Step

Let's trace through a real resolution:

// GrandchildComponent injects BiryaniService\nprivate service = inject(BiryaniService);\n\n// Step 1: Check GrandchildComponent's injector\n// โ†’ Not found (BiryaniService is at root)\n\n// Step 2: Check ParentComponent's injector\n// โ†’ Not found\n\n// Step 3: Check AppComponent's injector\n// โ†’ Not found\n\n// Step 4: Check Root Injector\n// โ†’ Found! (because @Injectable({ providedIn: 'root' }))\n// โ†’ Return the singleton instance

"Breadth-first search โ€” pehle apne level pe dhundho, phir upar jao."

This upward resolution means child components inherit their parent's services โ€” unless they override them by providing their own.

05Why DI is Powerful

Why is DI such a powerful pattern?

  • Testable โ€” Inject a mock service in unit tests. No need to modify component code.
  • Flexible โ€” Swap implementations without changing component code. LoggerService โ†’ ConsoleLoggerService.
  • Singleton by default โ€” One instance shared everywhere. Consistent state across the app.
  • Decoupled โ€” Component doesn't know HOW the service is created, just uses it.

"DI ka matlab โ€” component ko koi fikar nahi ki service kaise bani, bas use karo."

Key Takeaways

  • โœ… DI lets Angular provide dependencies โ€” you don't create them (like Swiggy delivery).
  • โœ… Injector is the container that holds and creates service instances.
  • โœ… Injectors form a hierarchy matching the component tree โ€” child checks parent up to root.
  • โœ… Resolution: component injector โ†’ parent โ†’ ... โ†’ root injector.
  • โœ… DI makes code testable, flexible, singleton-efficient, and decoupled.
Course Search
Search across all chapters & stages
๐Ÿ“–

Search the course

Type any topic โ€” branching, stash, rebase, hooks โ€” and jump straight to that chapter.

merge branchesgit stashundo commitrebase