DEV Community

Gaëtan Redin
Gaëtan Redin

Posted on • Originally published at Medium on

Angular: Lazy-loading & Nested RouterOutlet

Angular for Everyone: Part 12

How to Implement Lazy Loading in Angular

Hey, you know we are still looking for optimizations to get better performances. Once we have implemented Routing in our application, how to improve it? How to get the best from the Angular framework? I’m gonna try to give you an insight through the Lazy-loading feature. And as a bonus, we are gonna talk about nested RouterOutlet.

Angular Lazy-loading

The more your application grows more it costs (time, bundle size). By default, Angular preloads all your modules, even those which are not immediately necessary. That leads to getting big initial bundle sizes and having the most important load times. However, when you have implemented several routes into your application that probably follow a functional design (workflows), do you really need to load all of your modules? Most likely not. You have defined default routes, and it needs to be eagerly loaded, but what about others? Yes, it can wait to be called.

So how to transform an eagerly loaded route into a lazy-loaded one?

Suppose you have developed your feature with its routes defined in the app-routing.module.ts .

We have:

// app-routing.module.ts

_const_ routes: _Routes_ = [
  ...
  {
    path: ‘feature-4/:code’,
    component: Feature4Component,
  },
  ...
];
Enter fullscreen mode Exit fullscreen mode

Now let’s implement the lazy-loading for feature-4 with an example.

First, we need to create a specific routing module for the feature (I suppose the feature already exists and has its own module):

_const_ routes: _Routes_ = [
  {
    path: ':code', // parameterized root
    component: Feature4Component,
  }
];

@NgModule({
  imports: [RouterModule._forChild_(routes)], // be careful, use forChild method
  exports: [RouterModule]
})
_export class_ Feature4RoutingModule {
}
Enter fullscreen mode Exit fullscreen mode

Don’t forget to import it in the feature-4 module:

@NgModule({
  declarations: [Feature4Component],
  imports: [**Feature4RoutingModule**],
})
_export class_ Feature4Module {
}
Enter fullscreen mode Exit fullscreen mode

We update the app-routing.module.ts as below:

// app-routing.module.ts

_const_ routes: _Routes_ = [
  ...
  {
    path: ‘feature-4',
    loadChildren: () => _import_(‘./components/pages/feature4/feature4.module’).then(mod => mod.Feature4Module),
  },
  ...
];
Enter fullscreen mode Exit fullscreen mode

And that’s all. You have your feature-4, which will be loaded only when its route will be requested.

You can do it for all routes, sub-routes. But keep in mind that you don’t need to do it for the default route of your application just because it’s necessary to load it.

Tips : To get the parameter from the route (here: code), just do that in your feature4.component.ts:

@Component({
  selector: 'med-feature4',
  templateUrl: './feature4.component.html'
})
_export class_ Feature4Component _implements OnInit_ {
  _public_ currentCode!: _string_ | _null_;

  _constructor_(_private_ _activatedRoute: ActivatedRoute) {}

  _public_ ngOnInit(): _void_ {
    _this_.currentCode = _this_._activatedRoute.snapshot.paramMap.get('code');

    _// OR  

 this_  
  ._activatedRoute.paramMap.subscribe((param: _ParamMap_) => _this_.currentCode = param.get('code'));
  }
}
Enter fullscreen mode Exit fullscreen mode

Nested routes

Nested RouterOutlet is often looked for. Why? Because it allows to respect the DRY principle and not repeat some codes that are the same for children routes.

If we rework our feature-4. The current route is /feature-4/:code . We want to have a consulting page and an edit page for the entity corresponding to the given code. In both, we have buttons to access each one, and we can have a common header with main information. Do we really want to code this twice? Of course not.

We create two Components, Feature4EditComponent, and Feature4ConsultComponent (don’t forget to declare it into the Feature4Module).

Here's how to update the routing for the feature:

// feature4-routing.module.ts

_const_ routes: _Routes_ = [
  {
    path: ':code',
    **component: Feature4Component,**
    children: [
      {
        path: 'consult',
        component: Feature4ConsultComponent
      }, {
        path: 'edit',
        component: Feature4EditComponent
      }, {
        path: '', redirectTo: 'consult' // default route (optional)
      }, {
        path: '**', component: PageNotFoundComponent // don't forget it, it's not inherited 
      }
    ]
  }
];
Enter fullscreen mode Exit fullscreen mode

In the HTML, just add:

// feature4.component.html
...

<router-outlet></router-outlet>
Enter fullscreen mode Exit fullscreen mode

And yes, you have two RouterOutlet in your application. The RouterOutlet use the closest routing definition, which here is the feature4-routing.module.ts .

Conclusion

Now you really know the benefits of routing. Why it’s important to use it in your application in terms of performance (time and size) and terms of code (DRY). If you have a question(s), don’t hesitate, I always answer :-)

Here you can access my project I use for medium articles:

GitHub - GaetanRdn/medium-angular: This project is a support for my medium articles.

Thanks for reading.

Learn More

Discussion (0)