takeUntilDestroyed() (từ @angular/core/rxjs-interop) hoàn tất Observable khi context bị huỷ, thay cho mẫu destroy$ = new Subject() + ngOnDestroy thủ công.
export class SearchBox {
private destroyRef = inject(DestroyRef)
constructor() {
// works: called inside an injection context
this.search.valueChanges.pipe(takeUntilDestroyed()).subscribe(...)
}
ngOnInit() {
// NG0203 without an explicit ref — no injection context here
this.ws.messages$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(...)
}
}NG0203 nghĩa là bạn gọi một API cần injection context (inject(), takeUntilDestroyed() không tham số) ở nơi Angular không còn giữ context đó — trong ngOnInit, trong callback, trong hàm async sau await. Ba cách xử lý:
- Gọi trong field initializer hoặc constructor.
- Truyền DestroyRef tường minh: takeUntilDestroyed(this.destroyRef) (destroyRef phải được inject() ở constructor).
- Bọc bằng runInInjectionContext(injector, () => ...) khi thật sự cần.
Lưu ý: chỉ dùng cho stream sống lâu (form valueChanges, websocket, router events, interval). HTTP request đã tự hoàn tất sau một lần phát nên không cần — ưu tiên async pipe hoặc toSignal() để khỏi quản lý subscription.