Angular's Dependency Injection (DI) system lets you provide and consume services at different levels of the component tree. The DI hierarchy controls a service's scope and lifetime, deciding whether an instance is shared app-wide or isolated to a specific component subtree.
In Angular, providers can be registered at multiple levels:
providedIn: 'root' in a service or using providers in the root module.providers array of a specific NgModule.providers array in the @Component decorator.When a component asks for a service, Angular:
The first provider found in this search path decides which service instance the component receives.
// app.module.ts - DataService provided at the root injector
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { DataService } from './data.service';
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule],
providers: [DataService], // Single shared instance for the whole application
bootstrap: [AppComponent]
})
export class AppModule { }
// child.component.ts - DataService provided at the component level
import { Component } from '@angular/core';
import { DataService } from '../data.service';
@Component({
selector: 'app-child',
template: '<p>Child Component</p>',
providers: [DataService] // New instance for this component and its children
})
export class ChildComponent { }
ChildComponent and injects DataService will receive the root-level singleton instance provided by AppModule.ChildComponent and all its child components will receive a separate instance of DataService created by the component-level provider.DataService for ChildComponent, it first finds the provider declared in the component's providers array, so it does not use the root one.providedIn: 'root' in services for tree-shakable, app-wide singletons unless you need specific scoping.CounterService and provide it at the root. Inject it into two different components and verify that incrementing the counter in one component updates the value in the other.CounterService again in a child component's providers array. Observe that the child component now has its own separate counter.