Course Progress 78%

Angular Dependency Injection (DI)

Angular Dependency Injection, जिसे DI कहा जाता है, Angular framework का core mechanism है। DI का काम यह है कि components और services को उनकी dependencies खुद create करने की बजाय Angular से automatically मिलें। इससे code loosely coupled, testable और scalable बनता है।

इस chapter में हम Angular DI को basics से लेकर advanced concepts तक step-by-step समझेंगे, exactly उसी depth में जैसा official Angular documentation में है, लेकिन language simple और practical रखी गई है।

Dependency क्या होती है

Dependency का मतलब है कोई class या object जिसकी किसी दूसरी class को जरूरत होती है।

Example:

export class OrderComponent {
  constructor(private orderService: OrderService) {}
}

यहाँ OrderService, OrderComponent की dependency है।

Dependency Injection क्या है

Dependency Injection एक design pattern है जिसमें:

  • Class खुद dependency create नहीं करती
  • Dependency बाहर से provide की जाती है
  • Angular injector dependency का lifecycle manage करता है

Angular में DI automatically constructor के through काम करता है।

Without DI Problem

अगर DI use न करें तो code ऐसा होगा:

export class OrderComponent {
  orderService = new OrderService();
}

Problems:

  • Tight coupling
  • Testing मुश्किल
  • Replace करना hard

DI इन सभी issues को solve करता है।

Angular DI System Overview

Angular DI system तीन main parts से बना है:

  • Provider
  • Injector
  • Consumer (Component / Service)

Flow:

Provider → Injector → Consumer

Provider क्या होता है

Provider Angular को बताता है कि dependency कैसे create करनी है।

Example:

providers: [OrderService]

या modern approach:

@Injectable({ providedIn: 'root' })
export class OrderService {}

Provider register किए बिना DI काम नहीं करेगा।

Injector क्या होता है

Injector actual object create करता है और manage करता है।

Angular में injectors hierarchy में होते हैं:

  • Root Injector
  • Module Injector
  • Component Injector

Injector hierarchy DI behavior को control करती है।

Consumer कौन होता है

Consumer वो class होती है जो dependency use करती है।

constructor(private service: OrderService) {}

Angular injector automatically correct instance provide करता है।

Root Injector

providedIn: 'root' का मतलब:

  • Service root injector में registered है
  • पूरे application में single instance रहेगा
  • Application lifecycle तक alive रहेगा

यह default और recommended approach है।

Component-Level Injector

Service को component में provide किया जा सकता है:

@Component({
  selector: 'app-cart',
  providers: [CartService]
})
export class CartComponent {}

इस case में:

  • हर CartComponent को new instance मिलेगा
  • State isolate रहती है

यह scoped services के लिए useful है।

Hierarchical Dependency Injection

Angular injectors tree structure follow करते हैं।

Resolution process:

  • Angular पहले current injector में search करता है
  • न मिलने पर parent injector में जाता है
  • Root तक search करता है
@Component({
  providers: [LoggerService]
})

Child component parent की service override कर सकता है।

Injection Tokens

Interfaces directly inject नहीं हो सकतीं।

इसलिए InjectionToken use किया जाता है।

export const API_URL = new InjectionToken<string>('apiUrl');

Provide करना:

providers: [
  { provide: API_URL, useValue: 'https://api.example.com' }
]

Inject करना:

constructor(@Inject(API_URL) private apiUrl: string) {}

यह configuration-based DI के लिए बहुत important है।

useClass Provider

Default behavior:

providers: [AuthService]

Equivalent:

providers: [
  { provide: AuthService, useClass: AuthService }
]

Custom implementation के लिए:

providers: [
  { provide: AuthService, useClass: MockAuthService }
]

Testing में widely used है।

useValue Provider

Static values provide करने के लिए:

providers: [
  { provide: 'APP_NAME', useValue: 'My App' }
]

Inject करना:

constructor(@Inject('APP_NAME') name: string) {}

Simple configuration values के लिए useful है।

useFactory Provider

Dynamic logic के साथ dependency create करने के लिए:

providers: [
  {
    provide: LoggerService,
    useFactory: () => new LoggerService(true)
  }
]

Dependencies भी inject की जा सकती हैं:

useFactory: (config: AppConfig) => new ApiService(config.url),
deps: [AppConfig]

Advanced configuration scenarios में use होता है।

Optional Dependencies

Dependency optional हो सकती है।

constructor(@Optional() private logger?: LoggerService) {}

अगर provider available नहीं है तो error नहीं आएगा।

Self और SkipSelf

Injector resolution control करने के लिए:

constructor(
  @Self() private localService: LocalService,
  @SkipSelf() private parentService: ParentService
) {}

Advanced hierarchical DI में useful है।

Dependency Injection in Services

Services भी other services inject कर सकती हैं।

@Injectable({ providedIn: 'root' })
export class OrderService {
  constructor(private http: HttpClient) {}
}

DI सिर्फ components तक limited नहीं है।

Tree-Shakable Providers

providedIn approach tree-shaking support करता है।

Unused services bundle से remove हो जाती हैं।

@Injectable({ providedIn: 'root' })

Performance और bundle size optimization के लिए critical है।

Common DI Errors

  • NullInjectorError
  • Circular dependency
  • Provider not found

Example:

NullInjectorError: No provider for AuthService

Solution: Service properly provide करें।

Circular Dependency Problem

ServiceA → ServiceB  
ServiceB → ServiceA

Angular runtime error throw करता है।

Solution:

  • Logic refactor करें
  • Shared service introduce करें

DI Best Practices

  • Services में heavy logic रखें
  • Components lean रखें
  • providedIn: ‘root’ prefer करें
  • Component-level providers सोच-समझकर use करें
  • InjectionToken use करें configuration के लिए

DI कब Important होता है

Angular DI critical होता है:

  • Large-scale apps
  • Testable architecture
  • Configurable systems
  • Pluggable modules

Angular Dependency Injection Angular को powerful framework बनाता है। DI को सही तरीके से समझना और apply करना professional Angular development के लिए mandatory है। अगले chapter में हम Providers & Injection Tokens को और deep में explore करेंगे, जहाँ advanced DI configuration patterns discuss होंगे।