Angular 21 de Cero a Experto / Routing
Guards funcionales: el portero de cada ruta
No todas las páginas son para todos. El panel de admin exige estar logueado; una página de
edición quizá deba avisarte si sales con cambios sin guardar. Los GUARDS son porteros que
Angular consulta antes de activar (o dejar) una ruta: devuelven true para dejar pasar,
false para bloquear, o una redirección. En Angular moderno son simples FUNCIONES —gracias a
inject()—, mucho más ligeras que las clases que reemplazaron. Hoy los dominas.
El portero VIP
Un guard funcional CanActivateFn
Un guard de activación es una función que devuelve true (pasa), false (bloquea) o un
UrlTree (redirige). Como corre en contexto de inyección, usa inject() para consultar lo
que necesite:
import { inject } from '@angular/core';
import { CanActivateFn, Router } from '@angular/router';
import { AuthService } from './auth.service';
export const authGuard: CanActivateFn = (route, state) => {
const auth = inject(AuthService);
const router = inject(Router);
if (auth.estaLogueado()) {
return true; // pulsera OK → pasa
}
// sin sesión → redirige al login, recordando a dónde quería ir
return router.createUrlTree(['/login'], {
queryParams: { volverA: state.url },
});
};Y lo enchufas a la ruta con canActivate:
export const routes: Routes = [
{ path: '', component: ListaGastosComponent },
{
path: 'admin',
canActivate: [authGuard], // el portero corre antes de activar /admin
loadComponent: () => import('./admin.component').then((m) => m.AdminComponent),
},
];Devolver un UrlTree (con createUrlTree) es la forma correcta de redirigir desde un guard:
cancela la navegación actual y lanza otra hacia el login. El queryParams: { volverA: state.url }
recuerda el destino para volver tras iniciar sesión —el mismo patrón de "ruta protegida" que
hiciste en React—.
Antes (guard de clase) vs Ahora (guard funcional)
Los tipos de guard
Angular tiene varios porteros, cada uno para un momento distinto:
CanActivateFn— ¿puede ACTIVARSE esta ruta? (el más común: auth, permisos).CanActivateChildFn— ¿pueden activarse las rutas HIJAS de esta?CanDeactivateFn— ¿puede ABANDONARSE esta ruta? (avisar "tienes cambios sin guardar").CanMatchFn— ¿esta ruta siquiera COINCIDE? (útil para servir rutas distintas según permisos, y evita descargar el chunk lazy si no coincide).
Todos son funciones que devuelven boolean / UrlTree (o una Promise/Observable de eso,
para comprobaciones asíncronas).
La lógica del guard, en vivo
La decisión de un guard es lógica pura: dado un estado de sesión y un rol, ¿pasa o redirige?
Pruébala aquí (simulando inject con objetos directos):
En Angular real, auth y urlDestino vendrían de inject(AuthService) y del state.url, y
la redirección sería un router.createUrlTree(...). Pero la DECISIÓN —el corazón del guard—
es exactamente esta lógica, que puedes testear sola.
¿Qué debe devolver un guard funcional para REDIRIGIR al usuario en lugar de solo bloquearlo?
Mini-reto
En el playground: 1) añade un pagoGuard que reciba un Auth con un campo plan: "free" | "pro"
y redirija a /mejora-tu-plan si el usuario no es "pro"; 2) prueba los tres escenarios
(invitado, free, pro); 3) escribe cómo se vería como CanActivateFn real, con
inject(AuthService) y router.createUrlTree(...).
Qué sigue
Ya proteges rutas. Falta una pieza para páginas robustas: cargar los datos ANTES de mostrar la página, para que nunca aparezca vacía "parpadeando". Eso es un resolver, el tema de la próxima lección, que cierra la teoría del módulo antes del reto de routing.