Route guards
Guardianes de rutas: CanActivate
Angular puede controlar si podemos ir a una ruta o abandonarla utilizando guardianes (guards). Los guards se utilizan en combinación con el router de Angular. En esta sección, vamos a ver cómo evitar que el usuario vaya a una ruta específica si, por ejemplo, el usuario no ha iniciado sesión. Para lograr esto, utilizaremos el guard CanActivate.
Vamos a crear un guard que compruebe si la ruta tiene un identificador numérico válido asociado al parámetro id de la ruta. A partir de Angular 15, podemos implementar guardianes como funciones en lugar de clases.
La función del guard recibe 2 parámetros (el segundo parámetro generalmente no se utiliza y se puede omitir). En este ejemplo, comprobaremos que el identificador sea un número. Los guards pueden devolver un booleano indicando si se puede acceder al ruta o no. También pueden devolver un objeto URLTree para forzar la navegación a otra página cuando la ruta no se puede activar. Si la función devuelve true, Angular nos deja navegar a la ruta que tenga asociado ese guardián.
El comando para generar un guardián es: ng g guard nombre-guardian. Marcaremos con la techa espacio el tipo de guard que queremos crear y presionamos enter.

El método canActivate, además de devolver un valor directamente (boolean o UrlTree), también puede devolver el valor dentro de una promesa u observable. El router de Angular se suscribirá automáticamente a ese observable o promesa.
Por ahora no funcionará ya que falta un paso importante. Si pruebas la ruta /products/asdf, por ejemplo, te llevará al detalle del producto y la id tomará el valor 'asdf', lo que al convertir a número genera NaN (dará un error al intentar cargarlo)
Para utilizar este guard, debemos registrarlo en las rutas correspondientes (en este caso, la ruta a ProductDetailComponent). Para proteger una ruta, utilizamos la propiedad canActivate. Es un array porque podemos usar varios guards CanActivate en una sola ruta (si algún guard falla o devuelve alguna redirección, no se activará la ruta).
Si ahora probamos la ruta /products/asdf, nos devolverá a la raíz (página de productos) ya que la id no es numérica. Esta comprobación la podríamos haber hecho en el componente product-detail, sin embargo, es más eficiente comprobarlo con antelación y directamente no cargar la página de destino.
Guardianes de rutas: CanDeactivate
Un guard de tipo CanDeactivate permite que el usuario abandone la página actual solo si se cumplen ciertas condiciones. Por ejemplo, si el usuario está editando la información de algún producto y no ha guardado los cambios, podemos usar este guard para mostrarle un mensaje indicándole que guarde (o cancele) los cambios antes de abandonar la ruta. O simplemente preguntarle si desea salir sin guardar cambios.
Vamos a crear un guard de tipo CanDeactivate que nos pregunte si estamos seguros de abandonar la página sin guardar los cambios. Si respondemos que sí, nos permitirá abandonar la página (devolviendo true). En caso contrario (false) nos quedaremos donde estamos.

Al igual que antes, se lo tenemos que añadir a la ruta correspondiente, esta vez en el array canDeactivate. En este caso, debe ser una ruta asociada con el componente ProductFormComponent, ya que es lo que hemos especificado como tipo genérico en la función del guard.
Como se puede ver, al especificar el componente para este guard, solo podemos usarlo en rutas asociadas a este componente. Pero hay una manera de crear un guard CanDeactivate reutilizable. Crearemos una interfaz llamada CanComponentDeactivate con un método llamado canDeactivate, que todos los componentes que para los que necesitemos este tipo de guard, la puedan implementar.
En lugar de usar un componente como tipo genérico, usaremos esta interfaz, y devolveremos lo que el método canDeactivate de ese componente devuelva.
Ahora solo tenemos que implementar esta interfaz en aquellos componentes que queramos utilizar con este guard e implementar la lógica en el método canDeactivate de dicho componente.
Crearemos además un booleano que nos indique si el producto ha sido guardado o no, para que no pregunte en ese caso si queremos abandonar la página.
En el futuro veremos cómo comprobar si el formulario ha sido modificado para no preguntar al usuario en caso contrario.