Which @angular/* package(s) are relevant/related to the feature request?
router
Description
RouterOutlet already exposes activate, deactivate, attach, and detach events. This solves the problem from #25521 from the perspective of the component that owns the <router-outlet>.
However, there is still no convenient component-level API for a routed component itself to know that it has become attached to or detached from the active router tree.
This becomes important with nested routes and RouteReuseStrategy.
This lifecycle is useful for more than refreshing cached data. Examples include:
- refresh stale or cached data when a reused route becomes visible again;
- save and restore scroll position when a cached page is detached and reattached;
- pause and resume DOM-dependent work;
- redraw charts, editors, virtualized lists, or other UI that needs to react when its routed subtree becomes active again;
- suspend work while a cached route is detached without destroying the component.
Today, implementing this inside a routed component requires manually finding and subscribing to RouterOutlet instances up the injector hierarchy and combining their activate, attach, and detach events.
A working implementation of such an API exists in ng-elementum:
MillerSvt/ng-elementum@cafe7f3
Proposed solution
Provide injection-context lifecycle functions for routed components, for example:
import {
beforeDetach,
afterDetach,
afterAttach,
afterNextDetach,
afterNextAttach,
} from '@angular/router';
@Component({
template: `...`,
})
export class SearchPage {
private scrollTop = 0;
constructor() {
beforeDetach(() => {
this.scrollTop = this.scrollContainer.nativeElement.scrollTop;
});
afterDetach(() => {
this.pauseBackgroundWork();
});
afterAttach(() => {
this.refreshCachedData();
this.scrollContainer.nativeElement.scrollTop = this.scrollTop;
});
}
}
Suggested semantics:
beforeDetach(callback) runs immediately before the routed view is removed from its outlet.
afterDetach(callback) runs after the routed component/subtree has been detached and cached.
afterAttach(callback) runs when the component becomes part of the active routed tree.
- Initial route activation counts as the first attach.
- Attach runs again when the component itself or any cached ancestor route containing it is reattached.
- Detach hooks run when the component itself or any ancestor route is detached by
RouteReuseStrategy.
- A component should receive only one before/after detach cycle while becoming detached, even if several ancestor outlets are involved in the same navigation.
- Reattachment should produce one corresponding attach notification.
- One-shot variants such as
afterNextAttach, beforeNextDetach, and/or afterNextDetach could be provided if useful, similar to afterNextRender.
- Registration should happen in an Angular injection context and be automatically cleaned up when the component is destroyed.
Alternatives considered
Subscribe to RouterOutlet.attachEvents / detachEvents from the parent template
This works when the parent owns the relevant outlet, but it moves component-specific lifecycle logic into its container. A reusable routed component should be able to manage its own cached-state lifecycle.
It also becomes awkward for deeply nested routes, because an ancestor outlet can detach the entire subtree.
Inject only the nearest RouterOutlet
The nearest outlet is insufficient when an ancestor route is reused. Detaching the ancestor removes the whole subtree without requiring the descendant's own outlet to detach its active component.
Subscribe to Router navigation events
Navigation events describe navigations, not whether a particular component instance was detached, preserved, reattached, destroyed, or unaffected. Reconstructing the actual reuse lifecycle from router events and snapshots duplicates knowledge already present in RouterOutlet.
Handle this inside a custom RouteReuseStrategy
A reuse strategy knows when route handles are stored and retrieved, but pushing component-specific behavior into the strategy couples unrelated pages to centralized infrastructure and makes reusable components harder to encapsulate.
Use ngOnInit / ngOnDestroy
A reused routed component is intentionally not destroyed when detached, so these hooks cannot represent repeated detach/attach cycles.
This issue description was generated with the assistance of artificial intelligence.
Which @angular/* package(s) are relevant/related to the feature request?
router
Description
RouterOutletalready exposesactivate,deactivate,attach, anddetachevents. This solves the problem from #25521 from the perspective of the component that owns the<router-outlet>.However, there is still no convenient component-level API for a routed component itself to know that it has become attached to or detached from the active router tree.
This becomes important with nested routes and
RouteReuseStrategy.This lifecycle is useful for more than refreshing cached data. Examples include:
Today, implementing this inside a routed component requires manually finding and subscribing to
RouterOutletinstances up the injector hierarchy and combining theiractivate,attach, anddetachevents.A working implementation of such an API exists in
ng-elementum:MillerSvt/ng-elementum@cafe7f3
Proposed solution
Provide injection-context lifecycle functions for routed components, for example:
Suggested semantics:
beforeDetach(callback)runs immediately before the routed view is removed from its outlet.afterDetach(callback)runs after the routed component/subtree has been detached and cached.afterAttach(callback)runs when the component becomes part of the active routed tree.RouteReuseStrategy.afterNextAttach,beforeNextDetach, and/orafterNextDetachcould be provided if useful, similar toafterNextRender.Alternatives considered
Subscribe to
RouterOutlet.attachEvents/detachEventsfrom the parent templateThis works when the parent owns the relevant outlet, but it moves component-specific lifecycle logic into its container. A reusable routed component should be able to manage its own cached-state lifecycle.
It also becomes awkward for deeply nested routes, because an ancestor outlet can detach the entire subtree.
Inject only the nearest
RouterOutletThe nearest outlet is insufficient when an ancestor route is reused. Detaching the ancestor removes the whole subtree without requiring the descendant's own outlet to detach its active component.
Subscribe to
Routernavigation eventsNavigation events describe navigations, not whether a particular component instance was detached, preserved, reattached, destroyed, or unaffected. Reconstructing the actual reuse lifecycle from router events and snapshots duplicates knowledge already present in
RouterOutlet.Handle this inside a custom
RouteReuseStrategyA reuse strategy knows when route handles are stored and retrieved, but pushing component-specific behavior into the strategy couples unrelated pages to centralized infrastructure and makes reusable components harder to encapsulate.
Use
ngOnInit/ngOnDestroyA reused routed component is intentionally not destroyed when detached, so these hooks cannot represent repeated detach/attach cycles.
This issue description was generated with the assistance of artificial intelligence.