Skip to content
advanced Phase 5 · Services and Dependency Injection

Hierarchical Injectors

Scope service instances to components or keep them application-wide.

45m
0 problems
Topic Progress 0%

The Injector Hierarchy

Angular's DI system is hierarchical. Each component and directive has its own injector that inherits from its parent. This creates a tree of injectors that mirrors the component tree.

Injector Tree

RootInjector (providedIn: 'root')
├── AppComponent injector
│   ├── HeaderComponent injector
│   │   └── NavComponent injector
│   └── MainComponent injector
│       └── ChildComponent injector
└── LazyModule injector
    └── LazyComponent injector

Component-Level Providers

@Component({
  selector: 'app-user-list',
  template: `<app-user-card *ngFor="let user of users" [user]="user"></app-user-card>`,
  providers: [UserService], // New instance for this component subtree
})
export class UserListComponent {
  constructor(private userService: UserService) {}
}

Each UserListComponent gets its own UserService instance. Child components (UserCardComponent) receive the same instance.

Provider Scope Comparison

Scope Syntax Instance
Root providedIn: 'root' One per app
Module providedIn: SomeModule One per module
Component providers: [Service] One per component
Environment EnvironmentInjector App-wide, outside component tree

ViewProviders vs Providers

@Component({
  selector: 'app-parent',
  template: `<ng-content></ng-content>`,
  viewProviders: [Service], // Only available to this component's view, not projected content
})
export class ParentComponent {}
  • providers — available to the component, its view, and projected content
  • viewProviders — available only to the component's own view (not ng-content)

EnvironmentInjector and runInInjectionContext

EnvironmentInjector provides application-wide providers outside the component tree. It is useful for functional guards, resolvers, and utility functions.

EnvironmentInjector

import { EnvironmentInjector, inject, runInInjectionContext } from '@angular/core';

@Injectable({ providedIn: 'root' })
export class AppService {
  constructor(private envInjector: EnvironmentInjector) {}

  doSomething(): void {
    runInInjectionContext(this.envInjector, () => {
      const router = inject(Router);
      router.navigate(['/']);
    });
  }
}

createEnvironmentInjector

import { createEnvironmentInjector, EnvironmentInjector } from '@angular/core';

const parentInjector = inject(EnvironmentInjector);
const customProviders = [
  { provide: API_URL, useValue: 'https://custom-api.com' },
];

const childInjector = createEnvironmentInjector(customProviders, parentInjector);

Practical Use Case: Feature Flags

export const FEATURE_FLAGS = new InjectionToken<FeatureFlags>('FEATURE_FLAGS');

// In app.config.ts
export const appConfig: ApplicationConfig = {
  providers: [
    {
      provide: FEATURE_FLAGS,
      useValue: { newDashboard: true, betaFeature: false },
    },
  ],
};

// In a component
@Component({
  selector: 'app-dashboard',
  template: `
    @if (flags().newDashboard) {
      <app-new-dashboard />
    } @else {
      <app-old-dashboard />
    }
  `,
})
export class DashboardComponent {
  flags = inject(FEATURE_FLAGS);
}

When to Use Each Scope

Scenario Scope
HTTP client, auth service Root
Feature module services Module
Component-specific state Component
Configuration, feature flags Environment

Quiz

1. What does a component-level provider create?

Question 1 options

2. What is the difference between providers and viewProviders?

Question 2 options

3. What is EnvironmentInjector used for?

Question 3 options

Flashcards

Question

What is the Angular injector hierarchy?

Answer

A tree of injectors mirroring the component tree. Each component has its own injector that inherits from its parent.

Question

What does a component-level provider create?

Answer

A new instance scoped to that component and its children. Not shared with other components.

Question

What is EnvironmentInjector?

Answer

Application-wide injector outside the component tree. Used for configuration, feature flags, and functional guards.

Revision Notes

Key Takeaways

  • 1. Angular's DI is hierarchical — each component has its own injector
  • 2. Component providers create scoped instances
  • 3. viewProviders restrict access to the component's own view
  • 4. EnvironmentInjector provides app-wide providers outside the component tree

Interview Tips

  • • Explain the injector tree and how it mirrors the component tree
  • • Be ready to describe when to use each provider scope
  • • Mention EnvironmentInjector for functional patterns

Cheat Sheet

Hierarchical DI Cheat Sheet

Provider scopes:

// Root (app-wide singleton)
@Injectable({ providedIn: 'root' })

// Module
@Injectable({ providedIn: SomeModule })

// Component (per-component instance)
@Component({ providers: [Service] })

// Environment (outside component tree)
{ provide: TOKEN, useValue: value } // in app.config.ts

viewProviders vs providers:

  • providers — available to view + projected content
  • viewProviders — available only to the component's own view

Continue Learning