How to show a loading status for Angular lazy-loaded routes?

72 views Asked by At

I have an Angular 17 application which uses standalone components, the initial routes are set up like so in app.routes.ts

export const appRoutes: Array<Route> = [
  { path: '', redirectTo: '/dashboard', pathMatch: 'full' },
  {
    path: 'login',
    component: LoginComponent,
    title: 'Login',
  },
  {
    path: '',
    canActivateChild: [AuthGuard],
    loadChildren: () => import(`./app-authorized.routes`).then((r) => r.appAuthorizedRoutes),
  },
  { path: '**', redirectTo: '/dashboard' },
];

Once the user logs in they are authorized and redirected to /dashboard, and the app-authorized.routes.ts routes are loaded. Here is what that file looks like:

export const appAuthorizedRoutes: Array<Route> = [
  {
    path: 'dashboard',
    component: DashboardComponent,
    canActivate: [AuthGuard],
    title: 'Dashboard',
  },
  {
    path: 'settings',
    component: SettingsComponent,
    canActivate: [AuthGuard],
    title: 'Settings',
  },
  //etc...
];

An issue I have is that after logging in, there is a delay as the data loads and the UI looks strange. I have a navigation bar set to appear when authorized, which shows but the login component is also still showing - which is wrong.

After logging in and while the lazy-loaded chunks are loading, is there a way to display this progress in the UI somehow?

1

There are 1 answers

0
Chris Barr On

As it turns out when you use loadChildren in your route config there are Start/End events for the loading of these, perfect! When I log these out it's easy to see exactly what is happening

Angular Route Events RouteConfigLoadStart and RouteConfigLoadEnd

So this means adding a loader is now pretty simple

export class AppComponent implements OnInit {
  private readonly router = inject(Router);
  
  isLoadingRouteConfig = false;
  
  ngOnInit(): void {
    this.router.events.subscribe((ev) => {
      if (ev instanceof RouteConfigLoadStart) {
        this.isLoadingRouteConfig = true;
      } else if (ev instanceof RouteConfigLoadEnd) {
        this.isLoadingRouteConfig = false;
      }
    });
  }
}

and then in the template:

@if (isLoadingRouteConfig) {
    Loading...
} @else {
    <router-outlet></router-outlet>
}