It's common practice in angular space to cache reused components with the help of RouteReuseStrategy:
import { Injectable } from '@angular/core';
import {
ActivatedRouteSnapshot,
DetachedRouteHandle,
Route,
RouteReuseStrategy,
} from '@angular/router';
@Injectable()
export class CustomReuseStrategy extends RouteReuseStrategy {
private pool = new WeakMap<Route, DetachedRouteHandle>();
public shouldAttach(route: ActivatedRouteSnapshot): boolean {
return !!this.pool.get(route.routeConfig);
}
public retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle | null {
return this.pool.get(route.routeConfig);
}
public shouldDetach(route: ActivatedRouteSnapshot): boolean {
return (
route.routeConfig.data?.shouldReuse && !this.pool.get(route.routeConfig)
);
}
public store(
route: ActivatedRouteSnapshot,
handle: DetachedRouteHandle | null
) {
this.pool.set(route.routeConfig, handle);
}
public shouldReuseRoute(
future: ActivatedRouteSnapshot,
curr: ActivatedRouteSnapshot
): boolean {
return future.routeConfig === curr.routeConfig;
}
}
then new CustomReuseStrategy should be provided to the module:
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { ChildComponent } from './child/child.component';
import { CustomReuseStrategy } from './route-reuse-strategy';
import { NgModule } from '@angular/core';
import { RouteReuseStrategy, RouterModule } from '@angular/router';
@NgModule({
imports: [
...
providers: [
{
provide: RouteReuseStrategy,
useClass: CustomReuseStrategy,
},
],
})
export class AppModule {}
at this point angular router module registers the new strategy to reuse routes (from cache) and the instance of the strategy is available under Router#routeReuseStrategy.
Let’s define few routes to demonstrate the new RouterOutlet events (/c marked to reuse on the next activation):
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { RouteReuseStrategy, RouterModule } from '@angular/router';
import { ChildComponent } from './child/child.component';
import { CustomReuseStrategy } from './route-reuse-strategy';
@NgModule({
imports: [
RouterModule.forRoot([
{
path: 'a',
component: ChildComponent,
},
{
path: 'b',
component: ChildComponent,
},
{
path: 'c',
component: ChildComponent,
data: {
shouldReuse: true,
},
},
]),
BrowserModule,
],
declarations: [AppComponent, ChildComponent],
bootstrap: [AppComponent],
providers: [
{
provide: RouteReuseStrategy,
useClass: CustomReuseStrategy,
},
],
})
export class AppModule {}
and the app.component.html looks like (just a few links and the router-outlet with new attach/detach events):
<a routerLink="/a">navigate to /a</a> <br />
<a routerLink="/b">navigate to /b</a> <br />
<a routerLink="/c">navigate to /c</a> <br />
<router-outlet
(activate)="onActivate($event)"
(deactivate)="onDeactivate($event)"
(attach)="onAttach($event)" <--- the new event
(detach)="onDetach($event)" <--- the new event
></router-outlet>
An attach event emits every time when the RouteReuseStrategy instructs the outlet to reattach the subtree, and the detach event emits when the RouteReuseStrategy instructs the outlet to detach the subtree. So attach event will be emitted on the next re-navigation to the /c url instead of activate one, because the component was attached from cache and not instantiated.
Sources:
- All of the described code is available on StackBlitz (unfortunately angular 13 is not available yet on StackBlitz): https://stackblitz.com/edit/new-router-outlets-events?file=src/app/app.component.html
- Angular commit: https://github.com/angular/angular/commit/4f3beffdbfa974b380b2225f163d363dd17e10bd
Top comments (0)