En este artículo vamos a ver que es routing o rutas, como trabajar con ellas, y muchas más cosas. Si os parece ¡Comenzamos!

¿Qué es el routing o rutas de Angular?

Angular, está destinado a hacer aplicaciones complejas y con muchas funcionalidades. Por ello, es necesario poder navegar con nuestra aplicación a través de menús, que contienen un conjunto de enlaces (URL) que nos permitirán realizar la navegación web hacía ciertas partes de nuestra aplicación.

El routing, es un servicio mediante el cual podremos implementar una navegación basada en URL’s (rutas).

Diferencias entre ruta relativa y ruta absoluta:

– Una URL completa o Ruta absoluta: Incluye el nombre del dominio + el orden de directorios.

      • Ejemplo: www.google.com/coches/ferrari

-Una URL relativa o Ruta relativa: En cambio, sólo indica el orden de directorios.

      • Ejemplo: /coches/ferrari

Navegación clásica (basada en URL) vs navegación por routing/rutas

En nuestro día a día, habitualmente navegamos mediante a navegación web.

Si por ejemplo buscamos casa blanca en Google:

Y posteriormente pulsamos click sobre noticias, si prestamos mucha atención y nos fijamos veremos que dicha navegación realizará una petición hacía nuestro servidor lo que provocará que la página sea recargada:

Y finalmente, nos llevará a la respuesta de dicha petición:

En cambio la navegación por routing (también conocida como navegación por rutas) de Angular, es similar aunque no igual. Ya que tiene muchas similitudes con la navegación tradicional, también tiene peculiaridades.

Ya que, cuando realizamos una petición en Angular, lo que realmente hace este, al ya disponer de la aplicación al completo en el browser, es no recargar la página. Sino que, simplemente, cambia el componente por otro sin necesidad de tener que realizar una petición al servidor a excepción de que haya que hacer una petición de datos que lo haría internamente sin necesidad tampoco de recargar la página.

Por tanto, gracias al routing, lo que haremos, es cargar un componente u otro en una determinada parte de nuestra web, en función de la URL, sobre la que realizaremos la petición. Ya que cada una de las rutas de angular, nos proporcionarán un componente en concreto, gracias al routing.

Preparando nuestra aplicación para poder trabajar con routing

Para poder trabajar con routing es necesario realizar una configuración.

Para realizar dicha configuración tenemos dos maneras:

  • La manera sencilla, definimos un proyecto con routing cuando creamos el proyecto

Durante el proceso de creación de un proyecto en angular con ng serve, el asistente de creación de proyectos de Angular @angular/cli, nos pregunta sobre si deseamos añadir routing a nuestra aplicación:

Si respondemos Y (Yes), automáticamente el asistente de creación de proyectos se encargará de configurarnos el routing, Esta es la forma más sencilla de anadir routing a nuestra app. Y ya tenemos lista nuestra aplicación para trabajar con routing.

Una alternativa a esta opción sería escribir directamente ng new angular-basic --routing lo que nos activaría el routing en el proyecto y, por tanto, sería equivalente a pulsar Y sobre la pregunta de routing.

Si nos fijamos, si utilizamos ng new angularApp --routing, podemos ver que esta variante no nos pide si queremos trabajar con routing ya que se lo acabamos de indicar mediante al parámetro routing.

Analizando el routing al detalle

Ya sabemos cómo configurar nuestros proyectos, tanto si creamos uno inicialmente como si tenemos uno creado y queremos añadirle el routing manualmente. Pero antes de ver un ejemplo de routing, vamos a analizar el routing más al detalle para entenderlo al 100%.

Si miramos los archivos que nos va generado la creación de la estructura de nuestra aplicación de Angular, podemos ver que se nos ha generado un archivo app-routing.module.ts que ya nos da una pista de lo que ha hecho:

Si abrimos el proyecto, y buscamos dicho archivo por la ruta que nos aparece, podemos ver que realmente el archivo app-routing.module.ts no es nada más y nada menos que un módulo con un export. El cual, nos permitirá importarlo en nuestro módulo principal con el fin de poder trabajar con routing:

Recordad que el decorador NgModule indica que la clase anotada con dicha anotación es un módulo.

Si nos fijamos en el archivo app-routing.module.ts, podemos observar que existen imports hacía @angular/router, esto se produce debido a que el routing no forma parte del módulo de @angular/core (coloquialmente se suele decir del core de Angular) sino que como ya hemos visto forma parte del módulo de router).

Muestra de ello, es que si vamos a la documentación oficial de Angular, y aunque si nos funciona correctamente el autoimport de módulos de angular en principio no nos haría falta, podemos ver desde donde hay que importarlo y más detalle de lo que importamos:

Concretamente estamos importando:

@angular/router Implementa el servicio Angular Router, que permite la navegación de una vista a la siguiente a medida que los usuarios realizan tareas de la aplicación.
RouterModule Agrega directivas y proveedores para la navegación en la aplicación entre vistas definidas en una aplicación. Use el Routerservicio Angular para especificar de forma declarativa los estados de la aplicación y administrar las transiciones de estado.

Si nos fijamos, podemos ver que tenemos un array donde guardaremos nuestras rutas de nuestra aplicación. Para ello, es decir, para poder definir dichas rutas, se importar el módulo de typeScript @angular/router.

Y que posteriormente importamos RouterModule, para poder trabajar con la función forRoot donde asignamos como parámetro a dichas rutas.

Si queremos obtener más detalle, además de visitar a la documentación oficial de Angular, también podemos apoyarnos sobre el IDE y ver que proporciona Routes por ejemplo:

Las rutas estarán definidas en la constante routes, y posteriormente realizaremos RouteModule realizaremos el routing, gracias a un conjunto interno de directivas y  mediante al método .forRoot() sobre el que añadimos las rutas para poder trabajar con el routing correctamente.

Finalmente, vemos que si vamos al archivo app.component.html, en la última línea de nuestro template del componente principal, tenemos una especie de selector llamado <router-outlet></router-outlet>. Que aunque por el momento no sabemos desconocemos su significado, ni que es, os puedo adelantar que es un selector de un componente, y que se llame router outlet ya nos da una pequeña pista sobre lo que puede significar salida del router o algo así.

Lo que nos proporciona realmente el selector router-outlet, es un componente que es una especie de “contenedor dinámico”, mediante el cual incrutaremos dicho componente dinámico, el componente adecuado/asociado a la ruta (correspondiente) que hayamos activado en la aplicación. Por tanto, una parte del contenido de nuestro template será ahora dinámico.

Para poder trabajar con routing necesitamos tener dicho componente. En nuestro caso, borraremos toda la plantilla a excepción de dicho router-outlet.

El componente router-outlet, por tanto, lo que hace es renderizar el componente asociado a las rutas que hemos definido previamente dentro del array de routes en el module llamado app-routing.module.ts

  • Añadiendo routing un proyecto creado previamente sin routing

Bien, hasta aquí el camino feliz, pero ¿Qué pasa si tengo una aplicación sin routing? ¿Tengo que volver a crear el proyecto de nuevo? La respuesta es NO, no hace falta crear un proyecto de nuevo, podemos añadir el routing a mano, manualmente nosotros mismos. Aunque el añadir routing al crear el código con el asistente de @angular/cli es mucho más cómodo no hay problema en añadirlo nosotros manualmente.

Para resolverlo podemos hacer dos cosas:

1. Añadir el routing sobre nuestro modulo app.module.ts: aunque es un poco mas chapucero, lo correcto sería tenerlo separado el modulo principal de nuestra aplicación de las rutas. Tanto por tener todo desacoplado todo por su función (por funcionalidades), como por si nuestra aplicación crece mucho es recomendable mantener un cierto orden. Pero aunque no sería la manera más óptima de esta manera funcionaría y no necesitariamos realizar el export del módulo si quiera:

2. Creando un módulo y añadiendo el routing:

Para generar el módulo de routing vamos a utilizar ng generate module en este caso, vamos a mantener el nombre anterior del módulo app.routing, aunque lo podríamos llamar como quisieramos.

ng generate module app-routing –flat –module=app.module

Utilizamos los párametros de:

      • –flat: nos permitirá que el modulo app-routing se cree directamente dentro de app sin englobarse en un directorio.
      • –module=app.module: nos permitirá que el framework de Angular autoimporte el modulo que vamos a crear dentro de imports de nuestro modulo app.module.ts.

Y si nos fijamos, ya tenemos módulo hecho, ahora solamente tenemos que añadir eliminar el import de CommonModule, ya que este módulo no será un módulo tradicional/común.

Y finalmente, importar los módulos de TypeScript de RouterModule y Routes.

Una vez creado esto, solo nos faltará añadir el componente dinámico que añadirá el component asociado a la ruta activa:

Y ya lo tenemos listo nuestro proyecto para trabajar con routing de Angular.

Bien, ya hemos visto los dos caminos para configurar el routing en Angular. El camino fácil y el difícil de añadir routing a Angular, ninguno de los dos es mejor o peor sino que simplemente son dos alternativas a tener en cuenta dependiendo del punto sobre el que partimos. Es decir, si vamos a crear un proyecto desde 0 nos ayudaremos del asistente y, en caso contrario, si ya tenemos un proyecto creado lo crearemos manualmente.

Añadiendo rutas a nuestro enrutador:

Una vez hemos configurado nuestro proyecto con alguna de las maneras que acabamos de ver, vamos a empezar a añadir las rutas para que nuestro enrutador, pueda realizar el routing.

Para ello, primeramente, vamos a crear unos componentes:

Si nos fijamos estamos utilizando el parámetro –skip-tests en la creación del componente para que no nos cree el archivo de test de cada uno de los componentes. Y podemos ver como al realizar la creación de los componentes se autoimportan dentro del array de declarations de nuestro modulo principal app.module.ts lo que nos permitirá trabajar con estos componentes desde nuestra aplicación.

Recordamos que en nuestro template solamente tenemos:

Si nos fijamos, tenemos un component llamado GoogleComponent, dentro del array de Routes, añadimos entre {} dos propiedades separadas entre una coma. La primera, será path que será la ruta que escribiremos en el navegador, la segunda, será el component que añadiremos cuando escribamos esa ruta.

Si ahora arrancamos el proyecto, y vamos a la ruta localhost:4200, podemos ver que se nos carga la aplicación de Angular normalmente:

En cambio, si escribimos localhost:4200/google lo que hace Angular es detectar que la ruta activa a cambiado y por tanto, la busca dentro del routing, como existe, va a nuestro componente dinámico y carga dentro de dicho componente el template (la vista) del componente de Google.

Podemos añadir el resto de rutas del resto de los componentes.

Si nos fijamos anteriormente, ya hablemos sobre rutas relativas y rutas absolutas. En este caso, estamos trabajando sobre las rutas relativas.

Podemos hacer lo mismo con el resto de componentes:

Aunque con esto podríamos realizar una navegación, podemos ver que es bastante primitiva y que si no nos acordamos de la ruta relativa no podemos ir a nuestra página web.

De hecho, si nos fijamos cada vez que modificamos la ruta desde el navegador  y pulsamos enter, podemos ver que se nos recarga la página:

Esto se carga el propósito de SPA de no recargar la página constantemente.

Una posible solución a esto, podría ser trabajar con enlaces (la etiqueta <a>) de manera tradicional:

Si ahora pulsamos a ir a Amazon, vemos que la página también se recarga:

Y finalmente podemos ver que se nos carga el template del componente de amazon en el <router-outlet></router-outlet>:

Hasta ahora, ambas maneras recargan la página, entonces, ¿Qué alternativas tenemos a recargar la página? El uso de route link:

El atributo Router link asocia una ruta que en principio debería haber definido previamente en el el array de router dentro del modulo de routing (app-routing.module.apps) ya que sino nos redigirá a una ruta que posiblemente no exista de nuestra web.

Si ahora visitamos un enlace, podemos ver que nos redirige sin realizar la recarga de la página:

Además de estas rutas, podemos añadir dos rutas más que serán esenciales, la primera será la ruta de la web raíz, es decir, cuando escribamos localhost:4200. Y la segunda cuando escribamos cualquier ruta que no existe en nuestra aplicación.

Para ello, primeramente, vamos a añadir un crear un nuevo componente llamado index:

Y posteriormente, vamos a hacer que cuando visitemos la ruta raíz, se nos cargue dicho componente:

Si ahora escribimos localhost, vemos que nos lleva hacía el componente index.html:

Y finalmente podemos crear otra ruta hacía cualquier ruta que no exista dentro de nuestra aplicación. Para ello, añadimos dos ** en la ruta del path de la siguiente manera: path: '**', component: NotFoundComponent

Si vamos al navegador, podemos ver que si escribimos una ruta que no existe y estamos situados en la vista del componente de Google:

Cuando pulsamos a enviar, vemos que nos redirige hacía la template con el componente index.

Otra opción sería hacer que nos enviará hacía un componente llamado notFound y que nos mostrará que la página no existe.

Vamos a ver un ejemplo:

Para ello, creamos un componente llamado notFount y lo asociamos a cualquier ruta que no conozcamos:

Si ahora realizamos una petición hacía una ruta no asociada a ningún componente podemos ver que:

Es muy importante situar la última ruta a la ruta con el path: ‘**’ ya que lo capturará todas las rutas y por tanto, si ponemos rutas debajo, antes de pasar por dicha ruta, será capturada por nuestra ruta que engloba todas las rutas.

que no existan, es muy importante definir dicho componente al final del resto de definiciones de rutas. Ya que, sino

Rutas relativas VS rutas absolutas

En angular podemos trabajar con rutas relativas y absolutas de dos maneras. Que trabajemos con unas u con otras, depende de cómo definamos la ruta.

Vamos a ver un ejemplo:

– La primera manera de trabajar con rutas relativas y absolutas depende de cómo definimos nuestra ruta del path del array del router.

  • El prefijo ./representa la ruta relativa desde la ruta actual

  • Sin prefijo representa la ruta relativa desde la ruta actual

  • El prefijo /representa la ruta absoluta desde la ruta raíz

  • El prefijo ../representa la ruta relativa para subir un nivel desde la ruta actual. Se utiliza cuando queremos subir un nivel sobre la ruta actual, por ejemplo cuando tenemos dos componentes dentro de un directorio y queremos cargar un componente desde otro componente.

Es decir, todo lo que sea una barra sola “/” será una ruta absoluta y en cambio, todo lo que no sea una barra sola “/”, será una ruta relativa (./, ../, o sin nada)

– La segunda manera de definir rutas relativas sería el definir la estrategia de rutas. Para ello, podemos definir dos URLs.

El primer tipo de URL serían las rutas relativas:

{ path: 'google', component: GoogleComponent}

Que sería equivalente a escribir:

{ path: 'google', component GoogleComponent, pathMatch: 'prefix'}

Si queremos trabajar con rutas absolutas (completas) otra opción sería la de utilizar:

{ path: 'google', component:GoogleComponent, pathMatch: 'full'}

Con estas dos rutas del pathMatch,  “prefijo” (prefix) o “completa” (“full”) acabamos de ver la estrategia de búsqueda de rutas. Por defecto, el valor predeterminado si no se escribe nada es prefix.

De forma predeterminada, el enrutador verifica los elementos de la URL desde la izquierda para ver si la URL coincide con una ruta determinada y se detiene cuando hay una coincidencia. Por ejemplo, ‘/ team / 11 / user’ coincide con ‘team /: id’.

La estrategia de coincidencia de ruta “completa” coincide con la URL completa. Es importante hacer esto al redirigir rutas de ruta vacía. De lo contrario, debido a que una ruta vacía es un prefijo de cualquier URL, el enrutador aplicaría la redirección incluso cuando navegue al destino de la redirección, creando un bucle sin fin.

Hay que tener sumamente cuidado con combinar rutas relativas con rutas absolutas ya que si no podrá generar errores como el siguiente:

Esto es todo por hoy, espero que os haya gustado. Un saludo 🙂