routing with shared layout and with feature modules

Viewed 207

there are similar questions to my case, which I have read, but still I have to ask.

I'm developing an app, which has at this time this structure:

enter image description here

I have the main app component with a router-outlet and with this routing declaration:

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { AuthRootComponent } from './auth/authroot/authroot.component';
import { StartLayoutComponent } from './start-layout/start-layout.component';

const routes: Routes = [
  {
    path: '',
    component: AuthRootComponent,
  },
  {
    path: 'layout',
    component: StartLayoutComponent,
  },
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule],
})
export class AppRoutingModule {}

This works as expected. After login, I redirect to StartLayoutComponent which should be a common layout for all the other features of the app. In this component, as usual, I have an app bar and a side bar. The side bar holds a router outlet, where I want to render the features according to the clicks on the side bar items. The intention is, by clicking a side bar item a feature component appears in the layout without loading the layout component again. For this I have this code:

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { CompanyComponent } from 'src/app/masterdata/general/company/company.component';
import { StartLayoutComponent } from '../start-layout.component';

const routes: Routes = [
  {
    path: 'layout',
    component: StartLayoutComponent,
    children: [
      {
        path: 'masterdata/general/company',
        component: CompanyComponent,
      },
    ],
  },
];

@NgModule({
  imports: [RouterModule.forChild(routes)],
  exports: [RouterModule],
})
export class SidebarRoutingModule {}

Which has the unwanted side effect mentioned in this blog post, namely the StartLayoutComponent gets recreated and I would have all my feature routing configurations in this one file. And I don't want to load the feature modules lazily too.

Is there really no other way around this? Without recreating the layout component, without lazy loading and without blowing up the side bar routing config?

1 Answers

After searching the net, I found this git post, where exact this 'bug' is described. And it turns out, that it is intended, because if the route path isn't the same, the parent component has to be recreated, even the parent component itself is the same.

To overcome this issue, we can use the RouteReuseStrategy and define a custom route strategy. With this code we define that Angular should reuse the component, if both routes use the same component:

export class CustomRouteReuseStrategy extends BaseRouteReuseStrategy {
  shouldReuseRoute(
    future: ActivatedRouteSnapshot,
    curr: ActivatedRouteSnapshot
  ): boolean {
    // Reuse the route of the RouteConfig is the same, or if both routes use the
    // same component, because the latter can have different RouteConfigs.
    return (
      future.routeConfig === curr.routeConfig ||
      (!!future.routeConfig?.component &&
        future.routeConfig?.component === curr.routeConfig?.component)
    );
  }
}

And we need to register this class of course:

providers: [
    { provide: RouteReuseStrategy, useClass: CustomRouteReuseStrategy },
  ]

With this addition, everything is fine and working as intended.

Related