DEV Community

loading...
Cover image for Angular route: pathMatch='full', when to NOT use?

Angular route: pathMatch='full', when to NOT use?

raj_sekhar profile image Raj Sekhar ・4 min read

Past experience

While implementing default route (path: ''), most of of the articles and blogs use 'pathMatch' with value 'full'. When I was implementing the same in my previous project, I simply copied it due to time constraint and it worked. With basic research, I understood, '' will match with other routes "always" and so that might create cyclic redirection if pathMatch: 'full' is not defined.

Then I concluded, for empty paths, I just need to put pathMatch: 'full' to make it work.

{ path: '', component: HomeComponent, pathMatch: 'full' }
Enter fullscreen mode Exit fullscreen mode

New Day, new project

Now I was starting a new project where I had multiple <router-outlets> in nested form. And I wanted to make this app load faster by splitting codebase on route level. That is each route will have separate JavaScript chunks to keep main.js as small as possible and the initial load time will be faster.

// app-routing.module
const routes: Routes = [
  {
    path: '',
    loadChildren: () => import('./modules/home/home.module').then(x => x.HomeModule),
    pathMatch: 'full'
  },
  { path: 'login', loadChildren: () => import('./modules/login/login.module').then(x => x.LoginModule) },
  { path: '404', loadChildren: () => import('./modules/errors/page-not-found/page-not-found.module').then(x => x.PageNotFoundModule) },
  { path: 'unauthorized', loadChildren: () => import('./modules/errors/unauthorised/unauthorised.module').then(x => x.UnauthorisedModule) },
  {
    path: 'network-error',
    loadChildren: () => import('./modules/errors/network-error/network-error.module').then(x => x.NetworkErrorModule)
  },
  { path: '**', redirectTo: '404' }
];

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

And inside HomeModule I wanted to keep other routes that user can enter after the login process.

// home-routing.module.ts
const routes: Routes = [
  {
    path: '',
    component: HomeComponent,
    children: [
      { path: 'dashboard', loadChildren: () => import('../dashboard/dashboard.module').then(x => x.DashboardModule) },
      { path: '', redirectTo: 'dashboard', pathMatch: 'full' },
      { path: 'simcards', loadChildren: () => import('../simcards/simcards.module').then(x => x.SimcardsModule) },
      { path: 'requests', loadChildren: () => import('../requests/requests.module').then(x => x.RequestsModule) }
    ]
  }
];

@NgModule({
  imports: [RouterModule.forChild(routes)],
  exports: [RouterModule]
})
export class HomeRoutingModule {}
Enter fullscreen mode Exit fullscreen mode

I expected it to work just like before, as nothing much is changed. I only replaced component, with loadChildren, but it gave this error

ERROR Error: Uncaught (in promise): NoMatch$1: {}
    at resolvePromise (zone-evergreen.js:1213)
    at resolvePromise (zone-evergreen.js:1167)
    at zone-evergreen.js:1279
    at ZoneDelegate.invokeTask (zone-evergreen.js:406)
    at Object.onInvokeTask (core.js:28522)
    at ZoneDelegate.invokeTask (zone-evergreen.js:405)
    at Zone.runTask (zone-evergreen.js:178)
    at drainMicroTaskQueue (zone-evergreen.js:582)
Enter fullscreen mode Exit fullscreen mode

I was trying to understand what went wrong. Completely frustrated and clueless, because I was supposed to build the pages and work on new feature, but here I am, stuck at this stupid route configuration.

After lot (a lot) of dubugging, i figured out the routes defined inside HomeModule is not recognised. (yeah, the error was not very friendly and intuitive, neither was it pointing to any specific file like Angular usually does). And this error was new for me.

I know how nested routes work and how lazy loading works. But this is the first time, I am mixing both of of them, using lazy loaded modules inside nested routes. Googling made me realize, there is not many articles where people use both. :'-( But luckily I found one or two that was pointing me to the pathMatch keyword in the route configuration. I wanted to learn it properly this time, and this video helped me understand, as to why is pathMatch used in the first place.

So eventually I updated app-routing with this:

//app-routing.module.ts
const routes: Routes = [
  {
    path: '',
    loadChildren: () => import('./modules/home/home.module').then(x => x.HomeModule),
    pathMatch: 'prefix' // 'full' will not trigger child routes
  }, // more on pathMatch: https://www.youtube.com/watch?v=h33FECmtLAM
  { path: 'login', loadChildren: () => import('./modules/login/login.module').then(x => x.LoginModule) },
  { path: '404', loadChildren: () => import('./modules/errors/page-not-found/page-not-found.module').then(x => x.PageNotFoundModule) },
  { path: 'unauthorized', loadChildren: () => import('./modules/errors/unauthorised/unauthorised.module').then(x => x.UnauthorisedModule) },
  {
    path: 'network-error',
    loadChildren: () => import('./modules/errors/network-error/network-error.module').then(x => x.NetworkErrorModule)
  },
  { path: '**', redirectTo: '404' }
];
Enter fullscreen mode Exit fullscreen mode

Conclusion

{ path: 'home', component: HomeComponent, pathMatch: 'full' }
Enter fullscreen mode Exit fullscreen mode

If you have configured a route like above, Angular will check, only if full path in browser URL is exactly equal to 'home' (example.com/home), then that component/module will be triggered. When you try navigating to 'home/child-route', the full path is now not matching with 'home', and this gives error.

use pathMatch: 'prefix', especially if that route path is supposed to load a module dynamically, which will have other routes

If you were wondering about this solution:

{ path: 'home', component: HomeComponent, pathMatch: 'full' }
{ path: 'home/child-route', component: HomeChildComponent, }
Enter fullscreen mode Exit fullscreen mode

it does not work in the nested-route. The HomeChildComponent will be rendered in parent (the one present in app.component.html), but I want the HomeChildComponent to be rendered in <router-outlet> defined in home.component.html

Alt Text

Hope this article save someone's time.

You got a better solution? I am listening. :-)

Discussion (1)

pic
Editor guide
Collapse
kuetabby profile image
Ivan

thank you!