liveBook · Manning

Dependency injection

As explained in Modern Angular

Dependency injection is a software design technique in which a framework supplies an object's required dependencies rather than the object constructing them itself.

Dependency injection (DI) supplies a dependency where it is needed instead of requiring each consumer to construct it. In Angular, a consumer requests a token and the injector returns the value registered for that token. This avoids repeatedly constructing dependency chains such as HttpClient and lets consumers share service state rather than creating isolated copies. section 3.1.1 section 3.1.2

A provider maps an injectable token to a value or instance; injection retrieves that value. Traditional Angular code commonly requests a service through a constructor parameter, while providers can be registered on a component, through providedIn: 'root', or in application configuration. Component-level provision is simple but can become unsuitable as an application grows. section 2.3.2 section 3.1.2

Modern Angular DI keeps the underlying provider-and-lookup model while making composition less tied to classes:

  • Use inject() to obtain dependencies in supported injection contexts, rather than only through constructor parameters. section 1.2.1 section 3.0
  • Configure application-wide dependencies with standalone provider APIs such as provideRouter(routes) and provideHttpClient(). Use importProvidersFrom(...) when bridging providers from module-based APIs. section 2.3.2
  • Control lookup behavior with optional, self, skipSelf, and host rules. Optional injection returns null when no provider is found; self and skipSelf constrain where lookup begins. section 3.4.1

Configurable text truncation

A reusable truncation directive can inject a TruncateLimit InjectionToken as its default character limit, while still accepting an Input for a particular element. Registering { provide: TruncateLimit, useValue: 70 } establishes a wider default; inject(TruncateLimit, { optional: true }) ?? 80 preserves a fallback when no value is provided. A local Input such as [limit]="10" overrides the injected default for one use. section 3.4.2

Listing 3.1 Injector class for a naive implementation of a DI mechanism
class InjectionToken<T> {  #1
  constructor(public value: T) {}
}

class Injector {
  private readonly dependencies = new Map<
    InjectionToken<any>, any
  >();  #2

  provide<T>(dependency: T): InjectionToken<T> {  #3
    const token = new InjectionToken(dependency);
    this.dependencies.set(token, dependency);
    return token;
  }

  inject<T>(token: InjectionToken<T>): T {  #4
    const dependency = this.dependencies.get(token) as T;
    return dependency;
  }
}

A minimal injector makes the core mechanism visible: register a value under an InjectionToken, retain the mapping, then retrieve the matching value by token. section 3.1.2

DI lookup follows the injector tree from the current component toward the NullInjector. A provider can therefore supply a global configuration or a context-specific override, letting reusable code consume defaults while components isolate state or choose local behavior. section 3.4.1 section 3.4.2

Constructor-based DI remains supported, but inject() enables dependencies in function-oriented building blocks such as guards, resolvers, and interceptors. The DI framework itself is treated as stable even as Angular expands standalone and functional authoring patterns. section 3.0 section 1.4.5

How Modern Angular covers it

How deep it goes
Explains provider registration, token lookup, hierarchy modifiers, and a primitive injector implementation.
Examples
Demonstrates a minimal Injector and a configurable TruncateDirective for employee-table text.
What it assumes
Assumes familiarity with Angular components, services, constructors, and basic standalone or NgModule configuration.
What you can do after
Apply it via Angular providers, InjectionToken, and inject() to share services and configure reusable features.
How it connects
Connects InjectionToken, HttpClient, standalone APIs, NgModules, routing, and functional guards, resolvers, and interceptors.

Also explained in

Compare how 21 books explain dependency injection →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Modern Angular. The section links point to the parts of the book it draws on.