Dependency Injection (DI) is a design pattern where a class receives its dependencies from external sources rather than creating them internally. Angular has a built-in DI framework that provides dependencies to components, directives, pipes, and services. This makes your code more modular, testable, and maintainable.
Services are decorated with @Injectable to make them available to the DI system. The providedIn property specifies where the service is registered:
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root' // Singleton — one instance for the entire app
})
export class DataService {
constructor(private http: HttpClient) { }
getItems() {
return this.http.get('/api/items');
}
}
providedIn: 'root' creates a tree-shakeable singleton service available application-wide. If the service is never injected, it is tree-shaken from the bundle — reducing the final build size.The most common pattern. A single instance is shared across the application. Use providedIn: 'root' or add the service to the providers array of the root module.
Create a provider that uses a factory function to determine the dependency at runtime:
const loggerFactory = (http: HttpClient) => {
return environment.production
? new RemoteLoggerService(http)
: new ConsoleLoggerService();
};
@NgModule({
providers: [
{ provide: LoggerService, useFactory: loggerFactory, deps: [HttpClient] }
]
})
Substitute one implementation with another:
{ provide: ApiService, useClass: MockApiService }
Alias an existing provider to another token:
{ provide: OldLoggerService, useExisting: LoggerService }
Provide a static value or configuration object:
{ provide: 'API_URL', useValue: 'https://api.example.com/v2' }
Angular's DI is hierarchical. Each component can have its own injector that inherits from its parent. This allows different instances of a service at different levels of the component tree.
@Component({
selector: 'app-child',
providers: [DataService] // New instance for this component and its children
})
If a component does not define its own provider, it inherits from the parent injector, eventually reaching the root injector.
Marks a dependency as optional. If the dependency is not found, Angular injects null instead of throwing an error:
constructor(@Optional() private logger?: LoggerService) { }
Restricts resolution to the current component's injector only — does not check parent injectors:
constructor(@Self() private localService: LocalService) { }
Skips the current component's injector and resolves from the parent injector:
constructor(@SkipSelf() private parentService: ParentService) { }
Limits resolution to the host component's injector. Useful when a component is projected into another component via ng-content:
constructor(@Host() private hostService: HostService) { }
When you use providedIn: 'root', Angular creates a tree-shakeable provider. If the service is never injected, it is removed from the production bundle. This is the recommended approach for most application-wide services.
@Injectable({
providedIn: 'platform' // Singleton across multiple Angular apps on the same page
})
export class SharedService { }
Available options: 'root', 'platform', 'any', or a specific module.
Services can inject other services through their constructor:
@Injectable({ providedIn: 'root' })
export class OrderService {
constructor(
private http: HttpClient,
private authService: AuthService,
private logger: LoggerService
) { }
}
You learned about Angular's dependency injection system, including @Injectable, providedIn, various provider patterns (useClass, useExisting, useValue, useFactory), hierarchical injectors, DI decorators (@Optional, @Self, @SkipSelf, @Host), and tree-shakeable providers. These tools help you design loosely coupled, testable services.
ConfigService with providedIn: 'root' that reads environment-specific settings. Create a FeatureFlagService that depends on ConfigService. Use useFactory to conditionally provide either a live AnalyticsService or a no-op MockAnalyticsService based on the environment. Use @Optional to inject a CacheService that might not be provided.