Angular Tutorial 0/42 lessons ~6 min read Lesson 26

    Angular Advanced DI

    Learn Angular Advanced Dependency Injection, including injectors, hierarchical DI, providedIn, inject(), provider types, Injection Tokens, multi providers, lookup decorators (@Self, @SkipSelf, @Host, @Optional), route-level and feature DI, plugin architecture, enterprise best practices, and interview questions.

    Course progress0%
    Focus
    39 guided sections
    Practice signal
    Examples included
    Career prep
    Interview Q&A included

    Learning Objectives

    By the end of this lesson, you will understand:

    • What Dependency Injection (DI) is.
    • Why Angular uses DI.
    • How Angular's Injector works internally.
    • The Dependency Injection lifecycle.
    • Hierarchical Dependency Injection.
    • Root Injector.
    • Platform Injector.
    • Environment Injector.
    • Component Injector.
    • Route-level Injectors.
    • Tree-Shakable Providers.
    • The inject() API.
    • providedIn options (root, platform, any).
    • Class Providers.
    • Value Providers.
    • Factory Providers.
    • Existing Providers.
    • Injection Tokens.
    • Multi Providers.
    • Optional Injection.
    • @Self(), @SkipSelf(), @Host(), @Optional().
    • Feature-level DI architecture.
    • Plugin-based DI.
    • Enterprise DI best practices.
    • Common mistakes.
    • Advanced interview questions.

    Introduction

    Imagine TechLearningPro has hundreds of components.

    text
    Login Component
    Dashboard
    Course Component
    Quiz Component
    Certificate Component
    AI Tutor
    Admin Panel

    Every component needs services like:

    text
    Authentication
    Course Service
    Logger
    HttpClient
    Analytics
    Notification
    Configuration

    Should every component create these services using:

    typescript
    new AuthService()

    No.

    Angular automatically creates and manages these objects.

    This is called Dependency Injection (DI).

    What is Dependency Injection?

    Dependency Injection is a design pattern where Angular creates required objects (dependencies) and provides them to components or services.

    Instead of:

    typescript
    const service = new CourseService();

    Angular does:

    typescript
    constructor(
    private courseService: CourseService
    ){}

    Angular automatically injects the service.

    Why Dependency Injection?

    Without DI:

    text
    Component
    ↓
    new Service()
    ↓
    Hard Coupling

    Problems:

    • Difficult to test
    • Difficult to replace
    • Difficult to maintain

    With DI:

    text
    Component
    ↓
    Angular Injector
    ↓
    Service

    The component depends only on the contract, not object creation.

    Real-Time Example

    TechLearningPro

    text
    Course Component
    ↓
    CourseService
    ↓
    HttpClient
    ↓
    Backend API

    The component never creates CourseService.

    Angular injects it automatically.

    Angular DI Architecture

    text
    Application Starts
    ↓
    Create Root Injector
    ↓
    Register Providers
    ↓
    Component Requests Service
    ↓
    Injector Creates Service
    ↓
    Component Uses Service

    What is an Injector?

    An Injector is Angular's object factory.

    Responsibilities:

    • Create services.
    • Store services.
    • Reuse services.
    • Manage service lifetime.

    Architecture

    text
    Component
    ↓
    Injector
    ↓
    Create Object
    ↓
    Return Service

    Service Lifecycle

    Suppose:

    typescript
    @Injectable()
    export class AuthService {}

    Application starts.

    text
    Root Injector
    ↓
    AuthService
    ↓
    Singleton
    ↓
    Shared Everywhere

    Every component receives the same instance.

    Root Injector

    Most services use:

    typescript
    @Injectable({
    providedIn:'root'
    })

    Architecture

    text
    Application
    ↓
    Root Injector
    ↓
    AuthService
    ↓
    Every Component

    Only one instance exists.

    Tree-Shakable Providers

    Example:

    typescript
    @Injectable({
    providedIn:'root'
    })

    If the service is never used:

    text
    Angular Build
    ↓
    Unused Service
    ↓
    Removed

    Smaller bundles.

    Platform Injector

    Some services belong to the Angular platform itself.

    Architecture

    text
    Browser
    ↓
    Platform Injector
    ↓
    Applications

    Rarely used directly.

    Environment Injector

    Modern Angular introduces the Environment Injector.

    Architecture

    text
    Application
    ↓
    Environment Injector
    ↓
    Router
    ↓
    Feature
    ↓
    Component

    This supports standalone applications and route-level providers.

    Component Injector

    Services can exist only inside one component.

    Example:

    typescript
    @Component({
    providers:[
    CourseStore
    ]
    })

    Architecture

    text
    Course Component
    ↓
    CourseStore
    ↓
    Only This Component

    Destroy the component.

    The service also disappears.

    Route-Level Injector

    Modern Angular supports:

    typescript
    {
    path:'courses',
    providers:[
    CourseStore
    ]
    }

    Architecture

    text
    Route
    ↓
    Injector
    ↓
    CourseStore
    ↓
    All Child Components

    Excellent for feature isolation.

    Injector Hierarchy

    Angular searches upward.

    text
    Component Injector
    ↓
    Route Injector
    ↓
    Root Injector
    ↓
    Platform Injector

    If not found:

    Angular continues upward.

    How Angular Resolves Dependencies

    Suppose:

    typescript
    constructor(
    private logger:
    LoggerService
    ){}

    Angular searches:

    text
    Component?
    ↓
    Route?
    ↓
    Root?
    ↓
    Platform?
    ↓
    Error

    inject() API

    Modern Angular prefers:

    typescript
    logger = inject(
    LoggerService
    );

    Instead of constructor injection.

    Advantages:

    • Cleaner code
    • Better readability
    • Works inside functions

    providedIn Options

    Root

    typescript
    providedIn:'root'

    Singleton.

    Platform

    typescript
    providedIn:'platform'

    Shared across applications on the same page.

    Any

    typescript
    providedIn:'any'

    Creates separate instances for different injectors when appropriate, often useful with lazy-loaded boundaries.

    Class Provider

    typescript
    providers:[
    LoggerService
    ]

    Equivalent:

    typescript
    {
    provide:LoggerService,
    useClass:LoggerService
    }

    Value Provider

    Useful for configuration.

    typescript
    {
    provide:API_URL,
    useValue:
    'https://api.techlearningpro.com'
    }

    Architecture

    text
    Injector
    ↓
    API_URL
    ↓
    String

    Factory Provider

    Sometimes service creation is dynamic.

    typescript
    {
    provide:Logger,
    useFactory:loggerFactory
    }

    Architecture

    text
    Injector
    ↓
    Factory
    ↓
    Logger

    Existing Provider

    Reuse another service.

    typescript
    {
    provide:Logger,
    useExisting:ConsoleLogger
    }

    Both tokens reference the same instance.

    Injection Tokens

    Primitive values require tokens.

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

    Inject:

    typescript
    inject(API_URL);

    Architecture

    text
    Token
    ↓
    Injector
    ↓
    Value

    Multi Providers

    Useful for plugins.

    Example:

    typescript
    {
    provide:HTTP_INTERCEPTORS,
    multi:true,
    useClass:AuthInterceptor
    }

    Another:

    typescript
    {
    provide:HTTP_INTERCEPTORS,
    multi:true,
    useClass:LoggingInterceptor
    }

    Architecture

    text
    Injector
    ↓
    HTTP_INTERCEPTORS
    ↓
    Interceptor[]
    ↓
    Many Objects

    Optional Injection

    Sometimes dependency may not exist.

    typescript
    inject(
    LoggerService,
    {
    optional:true
    }
    );

    If missing:

    text
    null

    instead of an error.

    @Self()

    Search only current injector.

    text
    Current Component
    ↓
    Service?
    ↓
    Yes
    ↓
    Stop

    @SkipSelf()

    Ignore current injector.

    Start from parent.

    Architecture

    text
    Skip Current
    ↓
    Parent
    ↓
    Root

    @Host()

    Limit lookup to the current host boundary.

    Useful in advanced component composition scenarios.

    @Optional()

    Dependency may not exist.

    Application continues.

    Real-Time Example

    TechLearningPro

    text
    Root
    ↓
    Authentication
    ↓
    Logger
    ↓
    Analytics
    ---------------------
    Course Route
    ↓
    CourseStore
    ↓
    Course Components

    Authentication is global.

    CourseStore exists only for Course pages.

    Feature-Level Architecture

    text
    Application
    │
    ├── Authentication
    ├── Dashboard
    ├── Courses
    ├── Practice
    └── Admin

    Each feature owns:

    text
    Services
    Signals
    Stores
    Injectors

    Excellent scalability.

    Plugin Architecture

    text
    Plugin
    ↓
    Injection Token
    ↓
    Plugin Loader
    ↓
    Dynamic Service

    Perfect for enterprise platforms.

    TechLearningPro Architecture

    text
    Root Injector
    │
    ├── AuthService
    ├── Analytics
    ├── Logger
    ├── Theme
    │
    Course Route
    │
    ├── CourseStore
    ├── QuizStore
    └── ProgressStore
    ↓
    Course Components

    Enterprise Best Practices

    Prefer:

    • inject() over constructor injection where it improves readability.
    • Route-level providers.
    • Feature-level services.
    • Injection Tokens for configuration.
    • Multi Providers for extensibility.
    • Tree-shakable providers.

    Avoid:

    • Giant global services.
    • Everything inside the Root Injector.
    • Creating services using new.
    • Tight coupling.

    Common Mistakes

    Creating Services Manually

    Avoid:

    typescript
    const auth =
    new AuthService();

    Always let Angular create services.

    Too Many Root Services

    Not everything belongs in the Root Injector.

    Feature-specific state should remain inside feature injectors.

    Configuration Hardcoded

    Use:

    text
    InjectionToken
    ↓
    Configuration

    Instead of constants scattered across the application.

    Massive Services

    Split:

    text
    CourseService
    QuizService
    CertificateService
    ProgressService

    Instead of one 5,000-line service.

    Enterprise DI Architecture

    text
    Browser
    ↓
    Platform Injector
    ↓
    Root Injector
    ↓
    Route Injector
    ↓
    Component Injector
    ↓
    Component

    Each level owns only what it needs.

    Advanced interview questions

    Interview Prep

    Practice concise answers, then expand each card for the explanation.

    10 questions
    1BeginnerQuestionWhat is Dependency Injection?+

    Answer

    Dependency Injection is a design pattern where Angular creates and provides object dependencies instead of components creating them manually.
    2BeginnerQuestionWhat is an Injector?+

    Answer

    An Injector is Angular's container responsible for creating, storing, and providing service instances.
    3BeginnerQuestionWhat is `providedIn:'root'`?+

    Answer

    It registers the service with the Root Injector, creating a singleton instance shared across the application.
    4IntermediateQuestionWhy use `inject()`?+

    Answer

    inject() provides a concise way to obtain dependencies without constructor injection and is especially useful in standalone APIs, guards, interceptors, and factory functions.
    5IntermediateQuestionWhat are Injection Tokens?+

    Answer

    Injection Tokens allow Angular to inject values or interfaces that don't have a runtime class representation, such as configuration objects or primitive values.
    6IntermediateQuestionWhat are Multi Providers?+

    Answer

    They allow multiple implementations to be registered under the same token, commonly used for HTTP interceptors and plugin systems.
    7IntermediateQuestionDifference between Root Injector and Component Injector?+

    Answer

    The Root Injector provides application-wide singletons that are long-lived. A Component Injector exists only for that component subtree and is destroyed with the component.
    8AdvancedQuestionWhat is the Injector Hierarchy?+

    Answer

    Angular searches for dependencies from the nearest injector upward. Component → Route → Root → Platform.
    9AdvancedQuestionWhat is Tree-Shakable DI?+

    Answer

    Services registered with providedIn can be removed from production bundles if they are never used, reducing application size.
    10AdvancedQuestionWhat is the recommended enterprise architecture?+

    Answer

    Root → Authentication/Analytics → Feature Routes → Feature Stores → Signals → Components. This architecture keeps global services global and feature-specific services isolated.

    Summary

    Dependency Injection is one of Angular's core architectural strengths.

    text
    Application Starts
    │
    ▼
    Platform Injector
    │
    ▼
    Root Injector
    │
    ▼
    Route Injector
    │
    ▼
    Component Injector
    │
    ▼
    Service Resolution
    │
    ▼
    Components

    For TechLearningPro, an ideal DI architecture is:

    text
    Root Injector
    │
    ├── AuthService
    ├── HttpClient
    ├── AnalyticsService
    ├── LoggerService
    │
    ├── Angular Course Route
    │ ├── CourseStore
    │ ├── ProgressStore
    │ └── QuizStore
    │
    ├── Java Course Route
    │ ├── CourseStore
    │ └── PracticeStore
    │
    └── Admin Route
    ├── UserManagementService
    └── ReportStore

    The core principle: Let Angular create and manage your dependencies. Keep global services in the Root Injector, feature-specific state in route or component injectors, and use Injection Tokens and hierarchical DI to build scalable, testable, enterprise-grade Angular applications.

    Next Lesson

    Angular HTTP Interceptors — You'll learn:

    • Request lifecycle
    • Functional interceptors (HttpInterceptorFn)
    • withInterceptors()
    • JWT authentication
    • Token refresh flow
    • Request/response transformation
    • Global error handling
    • Retry strategies
    • Caching
    • Request deduplication
    • Correlation IDs
    • Logging and monitoring
    • Loading indicators
    • Enterprise interceptor architecture
    • Advanced interview questions
    Ready to mark this lesson complete?Track your journey across the entire course.