Angular Router - Children or LoadChildren?

Angular Router - Children or LoadChildren?

Angular Router: Children or LoadChildren?

(This article assumes basic awareness of routers and routers API. For in-depth understanding, please refer to Angular docs)

Angular Router is one of the most useful packages in the angular ecosystem. However, if you are new to Angular and just starting to work with routers, your goal would probably be to set up few basic routes. Moreover, with new developers, I have usually seen many questions around children and loadChildren properties. Therefore, this article will focus only on the differences between these two properties and when to use what.

Angular Route Interface

export interface Route {
  path?: string;
  component?: Type<any>;

  children?: Route[];
  loadChildren?: LoadChildren;

  ... few other properties
}

Let me start by quickly explaining the above four properties of the Route interface (that are in the scope of this article):

  • Path: The router API breaks down the entire URL into individual fragments. The path property could correspond to a combination of these fragments. It is mainly used to identify the angular component that should be instantiated and loaded in the parent's router outlet.
  • Component: This property refers to the angular component that should instantiate for this route.
  • Children: This property defines nested routes, and angular would load them upfront.
  • LoadChildren: It is also used to define nested routes, but Angular Router would lazily load them. You see the advantage here.

Now that we have defined relevant Route properties, let's take a look at when we should choose between childrenand loadChildren.

Use Children:

  • To add nested routes.
  • Angular would load all child components upfront.
  • Make sure you import all NgModules for each component defined in the nested route table. Otherwise, your code would not work.
  • To help with the readability and maintainability of your code, avoid this property if your route table's nesting is getting too long. My personal preference is < 3 levels max.
  • Ideal for simple routes.
  • Code example:
const routes = [ 
    { 
        path: '', 
        component: ApplicationFrameComponent, 
        children: [ 
            { 
                path: 'home', 
                component: HomeDashboardComponent, 
                children: [ 
                    { 
                        path: 'api-dashboard', 
                        component: ApiHomeDashboardComponent 
                    }] 
            }, 
            { 
                path: 'api-list', 
                component: ApiListComponent, 
                children: [ 
                    { 
                        path: 'internal', 
                        component: InternalApisListComponent 
                    }, 
                    { 
                        path: 'external', 
                        component: ExternalApisListComponent 
                    }] 
            }]
        }];

Use LoadChildren:

  • For lazy loading. Using this property will optimize your application's performance by only loading the nested route subtree when a user navigates to a particular URL that matches the current route path.
  • It helps in keeping the nested routes table separate.
  • You must specify a routing module for loadChildren. This module must define the routes and should import all relevant ng modules
  • If you use import(<module-path>).then(module => module.<routing-module>), Angular will create a separate js bundle that will be loaded only when a child route is activated. And you get better performance, code readability, and maintainability.
  • If you use () => <routing-module>, angular will not create a separate js bundle, but the routes table would be kept separate. The result is better code readability and maintainability. Performance would be the same as the children approach.
  • Code example:
const rootRoutes = [ 
    { 
        path: '', 
        component: ApplicationFrameComponent, 
        children: [ 
            { 
                path: 'home', 
                loadChildren: () => HomeDashboardRoutingModule 
            }, 
            { 
                path: 'api-list', 
                loadChildren: @import('./api-list.module').then(module => module.ApiListRoutingModule) 
            }] 
    }];

// In HomeDashboardRoutingModule
const homeRoutes = [ 
    { 
        path: '', 
        component: HomeDashboardComponent, 
        children: [ 
            { 
                path: 'api-dashboard', 
                component: ApiHomeDashboardComponent 
            }] 
    }]; 
    
// In ApiListRoutingModule 
const apiListRoutes = [ 
    { 
        path: '', 
        component: ApiListComponent, 
        children: [ 
            { 
                path: 'internal', 
                component: InternalApisListComponent 
            }, 
            { 
                path: 'external',
                component: ExternalApisListComponent 
            }]
    }];

I hope this article was helpful! A quick question for my audience. What would happen if we pass a component for a route with loadChildren property?

{ 
    path: 'home', 
    component: HomeDashboardComponent, 
    loadChildren: () => HomeDashboardRoutingModule 
}

Would you please reply in the comments section below?

About author
Anand is one of the founding ui engineer and an angular architect at Traceable AI. He is actively contributing in hypertrace-ui. You can find him on https://anandtiwary.dev/, github, twitter, linkedin and medium. Please reach out to him if you need any help with UI Development.
Open SourceAngularAngular RouterRouterTypescriptfrontendwebdevelopmentuiHypertraceanand tiwary