The new RouterOutlet events in Angular 13
Tags: angular, typescript, javascript, webdev
Published: 2021-11-01 15:05:16

It's common practice in angular space to cache reused components with the help of `RouteReuseStrategy`:
```typescript
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:
```typescript
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):
```typescript
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):
```html
<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