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 होंगे।
