๐Ÿณ IntuitiveFE
Login
โ† All concepts

Angular Routing Guards

โฑ๏ธ ~15-minute bite ยท solve the sandbox to master

0%lesson
๐Ÿง’

5-Year-Old Metaphor

โ€” The physical, real-world picture. No jargon.

Guards = airport security checkpoints at boarding. Each checkpoint has a different job.

  • canMatch = airline check โ€” is this even your flight? If not, you get directed to a different gate entirely.
  • canActivate= passport control โ€” can you enter the country? You're at the right gate but may still be turned away.
  • canActivateChild = gate check โ€” can you board this specific flight within the terminal?
  • resolve = the crew briefing before doors open. Data loads before passengers board โ€” no half-ready component.
  • canDeactivate= "are you sure you want to leave the gate area?" โ€” prevents accidental abandonment of unsaved work.
๐ŸŽ›๏ธ

Interactive Sandbox

โ€” Move something, see it react instantly.

Guard Chain Simulator

โ—‹ Match?
->
โ—‹ Enter?
->
โ—‹ Child?
->
โ—‹ Resolve
->
โ—‹ Leave?
CanActivateFn

Guards navigation to a route. Returns boolean (allow/deny) or UrlTree (redirect). The router has already matched this route โ€” canActivate decides if the user can enter.

ts
1import { CanActivateFn, Router, UrlTree } from '@angular/router';
2import { inject } from '@angular/core';
3import { map } from 'rxjs/operators';
4import { AuthService } from './auth.service';
5ย 
6// Simple boolean guard
7export const authGuard: CanActivateFn = (): boolean => {
8 const isLoggedIn = inject(AuthService).isLoggedIn();
9 if (!isLoggedIn) {
10 inject(Router).navigate(['/login']);
11 }
12 return isLoggedIn;
13};
14ย 
15// UrlTree redirect โ€” preferred over imperative navigate()
16export const authGuardWithUrlTree: CanActivateFn = (): boolean | UrlTree => {
17 const auth = inject(AuthService);
18 const router = inject(Router);
19 return auth.isLoggedIn()
20 ? true
21 : router.createUrlTree(['/login'], {
22 queryParams: { returnUrl: router.url }, // preserve intended URL
23 });
24};
25ย 
26// Async guard returning Observable
27export const roleGuard: CanActivateFn = (
28 route
29): Observable<boolean | UrlTree> => {
30 const requiredRole = route.data['role'] as string;
31 const router = inject(Router);
32 return inject(AuthService).currentUser$.pipe(
33 map(user =>
34 user?.roles.includes(requiredRole)
35 ? true
36 : router.createUrlTree(['/forbidden'])
37 )
38 );
39};
40ย 
41// Route definition
42export const routes: Routes = [
43 { path: 'admin', component: AdminComponent, canActivate: [authGuardWithUrlTree] },
44 { path: 'settings', component: SettingsComponent, canActivate: [authGuard, roleGuard],
45 data: { role: 'admin' } }, // multiple guards: all must return true
46];
  • โ†’Multiple guards in the array: Angular runs them in parallel (Angular 15+) โ€” all must pass
  • โ†’UrlTree redirect is preferred over imperative router.navigate() โ€” cleaner and testable
  • โ†’Returning an Observable: it must complete โ€” use take(1) or first() if it's a long-lived stream
1/5 explored
๐ŸŽฏ

Challenge

Explore all 5 guard types. Use the toggles to simulate guard pass/fail and run the chain.

Try it
๐ŸŽฏ

Why Should I Care?

โ€” The exact interview question + the bug it kills.

Q: What's the difference between canActivate and canMatch?

canMatch runs during route matching โ€” if it returns false, the router tries the next route definition for the same URL. canActivate runs after matching โ€” the route is already selected, and false blocks navigation (often redirecting). canMatch = 'does this route exist for you?'. canActivate = 'can you enter this route?'

Q: When should you use resolve vs fetching data in ngOnInit?

resolve prevents partially-loaded component views โ€” the component renders with data already present, no loading spinner needed inside the component. ngOnInit is simpler and better for non-critical or user-triggered data loads. Use resolve when missing data would leave the view in a broken state.

Q: Why prefer functional guards over class-based guards?

Functional guards (CanActivateFn) use inject() directly โ€” no DI class, no implements CanActivate boilerplate, no @Injectable(). They're tree-shakeable, easier to unit-test (just call the function), and the Angular team considers them the idiomatic path forward.

๐Ÿ”ฌ

The Deep Dive

โ€” Spec refs, engine internals, the minutiae.

Guard internals, return types, and advanced routing patterns:

  • 01

    inject() inside functional guards: works in the injection context of the guard call โ€” inject(Router), inject(AuthService), etc. No constructor needed.

  • 02

    UrlTree redirects: router.createUrlTree(['/login'], { queryParams: { returnUrl: router.url } }) โ€” the router processes the UrlTree as a navigation, not an imperative side effect. Cleaner and testable.

  • 03

    Guard return types in full: boolean | UrlTree | Observable<boolean | UrlTree> | Promise<boolean | UrlTree>. All forms are valid; Observable must complete.

  • 04

    canMatch for feature flags: define two routes with the same path. canMatch on the first checks the flag. If false, router falls through to the second route. Zero impact on the URL.

  • 05

    Angular 15+ parallel guard execution: multiple guards in a canActivate array run concurrently โ€” Angular waits for all before deciding. First falsy result wins (short-circuits).

๐ŸŽค

Interview Questions

โ€” Real questions from real interviews โ€” with answers.

canMatch runs during route selection; canActivate runs after a route is already matched.

UrlTree is declarative โ€” Angular processes it as part of navigation, making it testable and avoiding race conditions.

The guard's first argument is the component instance โ€” use an interface to avoid a tight import dependency.

A resolver pre-fetches data before the component renders โ€” the component always has data on first render, no loading state needed.

Functional guards use inject() directly โ€” no class, no @Injectable, no implements boilerplate, tree-shakeable.

Angular 15+ runs them in parallel โ€” all must return true. The first false short-circuits.

๐ŸŽฎ

Memory Game

โ€” Quick quiz โ€” lock the concept in long-term memory.
1/4

What is the difference between route children and loadChildren?