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
