liveBook · Manning

takeUntilDestroyed

As explained in Modern Angular

takeUntilDestroyed is an Angular RxJS interoperation operator that completes an observable when its associated destruction context is destroyed.

takeUntilDestroyed ties an RxJS subscription to an Angular destruction context. When that context is destroyed, the observable subscription is disposed of, removing repetitive teardown code from components. section 5.3.4 section 5.6

Use it in a pipe before subscribe when a component listens to a stream that should not outlive the component. In an employee editor, a permissions stream can disable private-name fields for users without private-edit permission. section 5.3.4

Pass DestroyRef outside an injection context

takeUntilDestroyed can obtain its destruction context through injection where injection is available. In lifecycle methods or other code outside that context, inject DestroyRef on the component and pass it explicitly: takeUntilDestroyed(this.destroyRef). section 5.3.4

For legacy teardown built with a destroy Subject and takeUntil, migration is usually direct: replace takeUntil with takeUntilDestroyed, remove the destroy Subject, and remove ngOnDestroy only if it has no unrelated work. Custom helpers can receive or inject DestroyRef when they need lifecycle-bound streams. section 5.3.4 section 5.5

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 example injects DestroyRef and passes it to takeUntilDestroyed from ngOnInit, where implicit injection is unavailable. section 5.3.4

Lifecycle-bound subscriptions also support shared notification use cases: each consuming component can establish its own connection, and destruction disposes that consumer’s subscription. Sharing the underlying observable across consumers remains a separate RxJS concern. section 7.3.3

How Modern Angular covers it

How deep it goes
Explains migration, injection-context limits, and explicit DestroyRef passing, while deferring shared-observable implementation details.
Examples
Uses an employee-permissions form and a notification connection consumed by a header component.
What it assumes
Assumes Angular components, RxJS observables, subscriptions, and dependency injection; introduces DestroyRef where lifecycle context is needed.
What you can do after
Apply it via Angular RxJS interop to replace lifecycle teardown Subjects and bind subscriptions to component destruction.
How it connects
Connects RxJS observables with DestroyRef, dependency injection, takeUntil, ngOnDestroy, signals, and toSignal.

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.