liveBook · Manning

Injection context

As explained in Modern Angular

An injection context is an Angular runtime context in which dependency-injection APIs can resolve providers and dependencies.

An injection context is the Angular runtime scope in which dependency injection can resolve a requested token through the active injector. Contexts differ as Angular creates components, directives, services, and other DI-managed classes, allowing the same token to resolve through different injectors when appropriate. section 3.1.4

The `inject` function does not make dependency injection available everywhere. It works during DI-managed class creation, field initialization, provider `useFactory` functions, `InjectionToken` factories, and functions called from a constructor’s active call stack. A class method such as `ngOnInit` runs after creation, outside that context, so calling `inject` there fails. section 3.1.4 section 3.2.2

Use the boundary deliberately:

  • Prefer field initializers with `inject` to remove constructors used only for dependency parameters. section 3.2.3
  • Keep helper functions that call `inject` on a creation-time path; do not invoke them later from arbitrary methods. section 3.2.2
  • When an API can accept a dependency explicitly, pass `DestroyRef` to use it outside an injection context. section 5.3.4
  • Set up a testing injector before directly constructing a service that uses `inject`. section 8.3.4

Context-aware authentication state

A standalone footer initializes `isAuth$` through an `isAuth()` helper that injects `AuthService`. This works because the field initializer runs while Angular creates the component. Moving the same call into `ngOnInit` would place it outside the injection context and produce an error. section 3.2.2

Listing 5.8 Using takeUntilDestroyed outside injection context
export class EditEmployeeComponent implements OnInit {
  permissionsService = inject(PermissionsService);
  destroyRef = inject(DestroyRef);  #1
  form = new FormGroup<EmployeeForm>({
    firstName: new FormControl('', {
      nonNullable: true,
      validators: [Validators.required],
    }),
    lastName: new FormControl('', { nonNullable: true }),
    email: new FormControl('', { nonNullable: true }),
    position: new FormControl('', { nonNullable: true }),
    level: new FormControl('', { nonNullable: true }),
  });

  ngOnInit() {  #2
    this.permissionsService.hasPermission('EditEmployeePrivateDetails').pipe(
      takeUntilDestroyed(this.destroyRef),  #3
    ).subscribe(hasPermission => {
      if (!hasPermission) {
        this.form.controls.firstName.disable();
        this.form.controls.lastName.disable();
        this.form.controls.email.disable();
      } else {
        this.form.controls.firstName.enable();
        this.form.controls.lastName.enable();
        this.form.controls.email.enable();
      }
    });
  }
}

This component retains `DestroyRef` from its creation-time context, then passes it to `takeUntilDestroyed` inside `ngOnInit`, where implicit injection is unavailable. section 5.3.4

Injection contexts can be confusing because `inject` looks like an ordinary function while depending on runtime timing. Unit tests that call `new AuthService()` bypass Angular’s context; `TestBed.runInInjectionContext` supplies one after providers and test dependencies are configured. section 3.2.4 section 8.3.4

How Modern Angular covers it

How deep it goes
Defines creation-time, initializer, factory, and call-stack contexts, then details lifecycle, RxJS, and testing consequences.
Examples
Uses authentication-state helpers in a footer, `takeUntilDestroyed` in `ngOnInit`, and AuthService unit-test setup.
What it assumes
Assumes familiarity with Angular dependency injection, components, services, constructors, and lifecycle methods.
What you can do after
Diagnose/debug with it by identifying invalid `inject` calls and supplying `DestroyRef` or a TestBed injection context.
How it connects
Connects `inject` with dependency injection, `InjectionToken`, `useFactory`, `DestroyRef`, `takeUntilDestroyed`, and TestBed.

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.