En la era moderna del desarrollo web, crear aplicaciones dinámicas e interactivas se ha convertido en la norma. Implementar funcionalidades exclusivas para ciertos usuarios, o disponibles bajo condiciones específicas, puede ser un reto muy complejo.
Por esta razón, Angular ofrece un sistema de enrutamiento basado en Rutas, reglas y componentes, permitiéndote diseñar fácilmente tus aplicaciones.

Pero antes de continuar, vamos a tener una breve revisión sobre Angular Router...


Angular Router Guardias y Resolvers

La libreríaAngular Router te permite gestionar la navegación dentro de tu aplicación Angular, definiendo una lista de Rutas.

Cada Ruta está definida por una serie de información, como la ruta para acceder a ella, el componente Angular a cargar, Rutas hijas y mucho más:

import { Route } from '@angular/router';
import { MyFeatureComponent, MyFeatureGuard } from './my-feature';

const routes: Route[] = [
  {
    path: 'my-feature',
    component: MyFeatureComponent,
    canActivate: [MyFeatureGuard],
    data: {
      id: "my-feature-id"
    }
  }
];

Puede proteger una o más Rutas, restringiendo el acceso o la salida, basándose en ciertas condiciones, utilizando funciones llamadas Guardias:

import { Route } from '@angular/router';
import { MyService } from './my-feature';

const myRoute: Route = [
  path: 'my-feature',
  canMatch: [() => inject(MyService).canMatch()],
  canActivate: [() => inject(MyService).canActivate()],
  canActivateChild: [() => inject(MyService).canActivateChild()],
  canDeactivate: [() => inject(MyService).canDeactivate()],
];

Hay cuatro tipos de Angular Guards, cada uno con una función diferente:

  • canMatch: se utiliza para verificar que una Ruta puede ser cargada. Puedes definir múltiples Rutas para una misma ruta y utilizar esta guarda para seleccionar sólo una basándote en ciertas condiciones;
  • canActivate: sirve para determinar si un usuario puede activar una ruta determinada. Por ejemplo, puede utilizarse para controlar el acceso a páginas reservadas únicamente a determinados usuarios;
  • canActivateChild: similar a canActivate, pero controla también el acceso a las rutas hijas de una ruta principal. Se ejecuta en cada navegación hacia una ruta hija, aunque se haya iniciado desde otra ruta hija;
  • canDeactivate: se utiliza para verificar si un usuario puede salir de una ruta determinada. Por ejemplo, se puede utilizar para pedir confirmación antes de salir de una página.

Nota: originalmente, los guardianes se implementaban como servicios inyectables. Tras la introducción de la funcióninject(), fue posible definirlos como funciones. Como resultado, las Guardias Inyectables están actualmente obsoletas.

Orden de ejecución de las Guardias durante la navegación

Además, puede utilizar funciones de Resolver para preparar datos para una Ruta:

import { Route } from '@angular/router';
import { MyService } from './my-feature';

const myRoute: Route = [
  path: 'my-feature',
  resolve: {
    user: () => inject(MyService).getUserInfo(),
    config: () => inject(MyService).getUserConfig()
  }
];

El uso de Resolvers es un gran enfoque para asegurar la presencia de datos antes de acceder a una Ruta, evitando lidiar con datos faltantes en una página.

Orden de ejecución de los Resolvers durante la navegación

Ahora que he cubierto lo básico, veamos cómo proteger tus Rutas redirigiendo a los usuarios a otro lugar.

Usa Guards y Resolvers para redirigir la navegación

Los Guardias de Angular te permiten impedir el acceso o la salida a una o más Rutas, bloqueando la navegación.

CPU
1 vCPU
MEMORIA
1 GB
ALMACENAMIENTO
10 GB
TRANSFERENCIA
1 TB
PRECIO
$ 4 mes
Para obtener el servidor GRATIS debes de escribir el cupon "LEIFER"

Sin embargo, para garantizar una experiencia de usuario más fluida, a menudo es preferible redirigir al usuario a otra Ruta.

Gracias a los Guards, podemos conseguirlo muy fácilmente, iniciando una nueva navegación antes de bloquear la actual:

import { inject } from '@angular/core';
import { Route, Router } from '@angular/router';
import { MyPage } from './pages/my-page';

const route: Route = {
  path: 'my-page',
  component: MyPage,
  canActivate: [
    () => {
      const router = inject(Router);

      router.navigate(['./my-other-page']);
      return false;
    },
  ],
};

Puede conseguir un resultado similar utilizando los Resolvers, iniciando una nueva navegación dentro de ellos

import { Route, Router } from '@angular/router';
import { MyService } from './my-feature';

const myRoute: Route = [
  path: 'my-feature',
  resolve: {
    user: () => {
      const router = inject(Router);

      router.navigate(['./my-other-page']);
      return null;
    }
  }
];

Redirigir con UrlTree

Alternativamente, puede redirigir la navegación haciendo que los Guards y Resolvers devuelvan un UrlTree que represente la nueva Ruta

import { inject } from '@angular/core';
import { Route, Router, UrlTree } from '@angular/router';
import { MyPage } from './pages/my-page';

const route: Route = {
  path: 'my-page',
  component: MyPage,
  canActivate: [
    () => {
      const router: Router = inject(Router);

      const urlTree: UrlTree = router.parseUrl('./my-other-page');
      return urlTree;
    },
  ],
};

Sin embargo, esta técnica no permite redirigir la navegación mediante NavigationExtras, como permitía la técnica anterior:

canActivate: [
  () => {
    const router = inject(Router);

    router.navigate(['./my-other-page'], { skipLocationChange: true });
    return false;
  }
]


Redirigir con RedirectCommand

Para superar esto, Angular v18 introduce una nueva clase RedirectCommand capaz de manejar NavigationExtras, permitiéndote redirigir la navegación en Guards y Resolvers:

import { inject } from '@angular/core';
import { RedirectCommand, Route, Router, UrlTree } from '@angular/router';
import { MyPage } from './pages/my-page';

const route: Route = {
  path: 'my-page',
  component: MyPage,
  canActivate: [
    () => {
      const router: Router = inject(Router);
      const urlTree: UrlTree = router.parseUrl('./my-other-page');

      return new RedirectCommand(urlTree, { skipLocationChange: true });
    },
  ],
};

La introducción de esta nueva clase RedirectCommand garantiza una gran facilidad de mantenimiento para Guardias y Resolvers.

Al haber sido diseñado específicamente para estos casos de uso, se puede ampliar fácilmente para adaptarse a cualquier nuevo parámetro necesario en el futuro.

Gracias por leer hasta aquí 🙏.

Fuente