typescript
32 lines · 5 steps
How a functional route guard works in Angular
A CanActivateFn checks authentication and either allows navigation or redirects to the login page.
Explained by
highlit
1import { inject } from '@angular/core';
2import {
3 ActivatedRouteSnapshot,
4 CanActivateFn,
5 Router,
6 RouterStateSnapshot,
7 UrlTree,
8} from '@angular/router';
9import { map, take } from 'rxjs/operators';
10import { Observable } from 'rxjs';
11import { AuthService } from './auth.service';
12
13export const authGuard: CanActivateFn = (
14 route: ActivatedRouteSnapshot,
15 state: RouterStateSnapshot,
16): Observable<boolean | UrlTree> => {
17 const auth = inject(AuthService);
18 const router = inject(Router);
19
20 return auth.isAuthenticated$.pipe(
21 take(1),
22 map((isAuthenticated) => {
23 if (isAuthenticated) {
24 return true;
25 }
26
27 return router.createUrlTree(['/login'], {
28 queryParams: { returnUrl: state.url },
29 });
30 }),
31 );
32};
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1Functional guards use inject() to grab services instead of a constructor, keeping them lightweight and tree-shakable.
- 2take(1) completes the stream after one emission so the guard resolves promptly instead of leaving navigation hanging.
- 3Returning a UrlTree from a guard is Angular's idiom for redirecting rather than manually calling navigate.
Related explainers
typescript
import { registerLocaleData } from '@angular/common'; import localeFr from '@angular/common/locales/fr'; import localeFrExtra from '@angular/common/locales/extra/fr'; import localeDe from '@angular/common/locales/de';
Locale-aware bootstrapping in Angular
i18n
localization
dependency-injection
Intermediate
8 steps
typescript
import { Module } from '@nestjs/common'; import { ConfigModule } from '@nestjs/config'; import * as Joi from 'joi';
Validating env config at boot in NestJS
configuration
schema-validation
environment-variables
Intermediate
8 steps
java
@Component @Converter public class EncryptedStringConverter implements AttributeConverter<String, String> {
Transparent column encryption in Spring & JPA
encryption
aes-gcm
jpa-converter
Advanced
10 steps
python
import time import uuid from django.utils.deprecation import MiddlewareMixin
Attaching per-request context in Django
middleware
request lifecycle
multi-tenancy
Intermediate
7 steps
typescript
import { Inject, Injectable, Logger } from '@nestjs/common'; import { CACHE_MANAGER } from '@nestjs/cache-manager'; import { Cache } from 'cache-manager'; import { InjectRepository } from '@nestjs/typeorm';
A cache-aside country lookup in NestJS
cache-aside
dependency-injection
batch-lookup
Intermediate
8 steps
java
package com.acme.billing.config; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.ConfigurationProperties;
Feature-flagged beans with Spring @ConditionalOnProperty
feature-flags
conditional-beans
strategy-pattern
Intermediate
5 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/how-a-functional-route-guard-works-in-angular-explained-typescript-7a02/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.