Angular route: pathMatch='full', when to NOT use?
Tags: angular, javascript, webdev
Published: 2021-02-27 13:29:17

## 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.

```js
{ path: '', component: HomeComponent, pathMatch: 'full' }
```

## 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](https://web.dev/route-level-code-splitting-in-angular/). 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**. 

```js
// 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 {}
```
And inside `HomeModule` I wanted to keep other routes that user can enter after the login process.

```js
// 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 {}
```

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

```shell
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)
```
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](https://medium.com/ngconf/how-to-nest-lazy-loaded-modules-2d73a7881be) or [two](https://www.freakyjolly.com/angular-nested-routing-with-multiple-routeroutlet-using-loadchildren-having-own-router-modules-example-application/) 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](https://www.youtube.com/watch?v=h33FECmtLAM).

So eventually I updated app-routing with this: 

```js
//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' }
];
```

## Conclusion
```js
{ path: 'home', component: HomeComponent, pathMatch: 'full' }
```
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:
```js
{ path: 'home', component: HomeComponent, pathMatch: 'full' }
{ path: 'home/child-route', component: HomeChildComponent, }
``` 
**it does not work in the nested-route**. The `HomeChildComponent` will be rendered in parent <router-outlet> *(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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aqru9f1l6o6rxddqgh8o.png)

Hope this article save someone's time. 

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