Guards & Lazy Loading

Preview — 3 of 10 questions

How do you implement a route guard in Angular 15+ standalone style?

javascript
// auth.guard.ts
import { CanActivateFn, Router } from '@angular/router';
import { inject } from '@angular/core';

export const authGuard: CanActivateFn = (route, state) => {
  const authService = inject(AuthService);
  const router = inject(Router);

  if (authService.isAuthenticated()) {
    return true;
  }

  // Redirect to login with return URL
  return router.createUrlTree(['/login'], {
    queryParams: { returnUrl: state.url },
  });
};

// pro.guard.ts
export const proGuard: CanActivateFn = () => {
  const userService = inject(UserService);
  const router = inject(Router);

  return userService.currentUser$.pipe(
    map(user => user?.plan === 'PRO' || router.createUrlTree(['/upgrade'])),
    take(1),
  );
};

// app.routes.ts
export const routes: Routes = [
  {
    path: 'dashboard',
    component: DashboardComponent,
    canActivate: [authGuard],
  },
  {
    path: 'pro-features',
    component: ProFeaturesComponent,
    canActivate: [authGuard, proGuard],  // both must pass
  },
];
ACreate a class implementing CanActivate and provide it with { provide: CanActivate, useClass: MyGuard }
BDecorate a method with @Guard() in the component class
CWrite a function matching CanActivateFn and add it to the route's canActivate array
DOverride the Router.navigate() method with custom logic

When would you use a CanDeactivate guard?

javascript
// can-deactivate.guard.ts
export type CanComponentDeactivate = {
  canDeactivate: () => boolean | Observable<boolean>;
};

export const unsavedChangesGuard: CanDeactivateFn<CanComponentDeactivate> = (component) => {
  return component.canDeactivate?.() ?? true;
};

// edit-form.component.ts
@Component({ selector: 'app-edit-form', template: '...', standalone: true })
export class EditFormComponent implements CanComponentDeactivate {
  form = new FormGroup({ /* ... */ });
  private initialValue = this.form.value;

  canDeactivate(): boolean | Observable<boolean> {
    if (!this.form.dirty) return true;

    // Show confirmation dialog
    return inject(DialogService).confirm({
      title: 'Unsaved Changes',
      message: 'You have unsaved changes. Leave anyway?',
      confirmText: 'Leave',
      cancelText: 'Stay',
    });
  }
}

// Route config:
{
  path: 'edit/:id',
  component: EditFormComponent,
  canDeactivate: [unsavedChangesGuard],
}
ATo prevent users from navigating to a protected route
BTo validate route parameters before activating a component
CTo clean up component resources before destruction
DTo prevent navigation away from a route — e.g., when a form has unsaved changes

What is the correct way to lazy-load a component in Angular 17+ standalone routing?

javascript
export const routes: Routes = [
  // Lazy-load a standalone component
  {
    path: 'admin',
    loadComponent: () =>
      import('./admin/admin.component').then(m => m.AdminComponent),
  },

  // Lazy-load child routes (from a separate file)
  {
    path: 'dashboard',
    loadChildren: () =>
      import('./dashboard/dashboard.routes').then(m => m.DASHBOARD_ROUTES),
  },

  // Lazy-load a group of routes with shared providers
  {
    path: 'shop',
    loadChildren: () => import('./shop/shop.routes').then(m => m.SHOP_ROUTES),
    providers: [ShopService, CartService],  // scoped to /shop and children
  },
];

// dashboard/dashboard.routes.ts
export const DASHBOARD_ROUTES: Routes = [
  { path: '', component: DashboardHomeComponent },
  { path: 'analytics', component: AnalyticsComponent },
];
A{ path: 'admin', component: () => import('./admin.component') }
B{ path: 'admin', module: () => import('./admin/admin.module') }
C{ path: 'admin', component: AdminComponent, lazy: true }
D{ path: 'admin', loadComponent: () => import('./admin/admin.component').then(m => m.AdminComponent) }

Sign up free to play

Answer all 10 questions (7 more), see explanations for every answer, and track your score.