Search code examples
angularlazy-loadingangular-standalone-componentsangular-lazyloadingangular17

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


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?


Solution

  • 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>
    }