routing guia completa portada

Routing en Angular : Guía completa : Parte 1

Última actualización:

Introducción al Routing

Angular nos permite construir single page applications (SPAs, por sus siglas en inglés). Lo hace usando una herramienta que trae por defecto, el Angular Router. Con el Router podremos crear varias páginas con distintas URLs, tipo /user, /register, etc, sin necesidad de crear otro documento HTML a parte del que ya viene con Angular, el index.html. 

rutas = routes

Estado inicial de nuestra demo

Para explicar cómo funciona el Routing, vamos a construir una pequeña demo-app. Consiste en una app que sirve para gestionar servidores y usuarios. Utilizaremos Bootstrap para tener una UI decente a la velocidad del rayo.

1. Puedes descargar la app (desde "Clone or download", con la opción "Download ZIP") en su estado inicial desde aquí.

2. Descomprime el ZIP en la carpeta de tu pc que elijas. 

3. Navega con tu terminal hasta la carpeta de tu proyecto y usa el comando npm install para instalar todas las dependencias. 

4.  Lanza el proyecto con ng serve -oque te lo abrirá en tu servidor local (en inglés, local host local server). El aspecto inicial de la app debería ser este:

demo app routing - estado inicial

En la parte superior tenemos 3 pestañas (en inglés, tabs), que reaccionar al pasar el ratón por encima, pero que no tienen configurada ninguna funcionalidad. Vamos, que no hacen nada 🐼.

Todo el contenido que se ve en esa página es el contenido que vamos a distribuir a lo largo de las 3 pestañas, generando así 3 "páginas".

Esto significará también que en la barra de navegación veremos, en lugar de http://localhost:4200rutas como http://localhost:4200/users, http://localhost:4200/servers, etc.

Cómo registrar y cargar rutas

Si exploras el código de la app, verás que está dividido en 3 secciones:

  • home
  • servers, con sub-secciones para gestionar un servidor individual, editar servidores y un servicio para cargar servidores y actualizarlos
  • users, con una sub-sección individual para cada usuario.

Todas son usadas en el AppComponent, y como ves, en estos momentos todas se muestran a la vez en la misma pantalla. Vamos a cambiar eso, de manera que, cuando hagamos clic en alguno de estos botones:

        <li class="nav-item"><a class="nav-link active" href="#">Home</a></li>
        <li class="nav-item"><a class="nav-link" href="#">Servers</a></li>
        <li class="nav-item"><a class="nav-link" href="#">Users</a></li>

éstos nos dirijan a la sección adecuada y sólo muestren esa sección en la página. Es decir, vamos a configurarlos para que cada uno de ellos cargue una ruta distinta que apunte a la sección (al componente) correspondiente en cada caso. 

Esas rutas deben estar registradas de alguna manera en nuestra app para que Angular tenga constancia de ellas. Ya que queremos que cada vez que alguien escriba, por ejemplo, esta URL: http://localhost:4200/users, el usuario sea dirigido a la página de users (es decir, al UsersComponent), tiene sentido que lo que necesitemos sea un comportamiento global, configurado al nivel más alto de nuestra app. Por eso, el lugar donde debemos registrar nuestras rutas es en el app.module.ts

1. Antes del decorador ngModule, añadimos una constante a la que llamamos appRoutesEs un nombre adecuado, ya que va a contener todas las rutas de nuestra app.

Esta constante (una const) será de tipo Routesun paquete que debemos importar desde angular/routes.

La const contendrá un array, ya que dentro vamos a crear múltiples rutas. Cada ruta será un objeto de JavaScript (en adelante, JS).

Una ruta debe seguir una estructura específica dada por Angular, que se compone de: 

N
O
M
B
R
E

Un path.

El nombre en la URL, que debe ser un string.

Éste se colocará detrás de http://localhost:4200, añadiendo automáticamente la barra (/). Por ejemplo, si le indicamos como path "servers", el resultado será http://localhost:4200/servers

A
C
C
I
Ó
N

Un componente (normalmente).

Define qué sucede cuando Angular detecta que la URL cambia (por ejemplo, de http://localhost:4200 a http://localhost:4200/users).

Al indicarle un componente, Angular lo carga, mostrando su template (su archivo HTLM, es decir, mi-componente.component.html).

2. Añadimos la ruta para users, vinculándola al componente Users.

3. Creamos una ruta vacía, es decir, una con un path: ' '. Ésta es una de las maneras de crear una homepage. Esto es, una ruta que Angular cargue cuando inicies tu app, la primera página que quieres que se vea. Normalmente, ésta será http://localhost:4200 o, algo más real, http://miweb.com, sin ningún término adjunto después.

4. Vinculamos la ruta vacía con el HomeComponent.

5. Creamos una ruta para servers y la vinculamos con el ServersComponent.

Con esto, sólo hemos completado una parte de la operación de registro de nuestras rutas 🥴. 

6. Añadimos el RouterModule al array "imports" y lo importamos desde angular/router.

7. Registramos las rutas llamando al método forRoot del RouterModule, y le pasamos nuestra const appRoutes.

export const appRoutes: Routes = [
  { path: '', component: HomeComponent },
  { path: 'users', component: UsersComponent },
  { path: 'servers', component: ServersComponent },
];

@NgModule({
  declarations: [
    AppComponent,
    HomeComponent,
    UsersComponent,
    ServersComponent,
    UserComponent,
    EditServerComponent,
    ServerComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    RouterModule.forRoot(appRoutes)

Una vez registradas las rutas, Angular queda informado, pero aún no sabe en qué lugar de la app debe mostrar el componente asociado a la ruta que corresponda 🙄. 

Écha un vistazo al app.component.html. Ahí verás que cargamos esos 3 componentes que hemos vinculado con rutas. Hasta ahora, Angular sabe que el selector <app-users> es el componente Users, que está vinculado con la ruta users. Pero eso no es suficiente, ya que no sabe en qué lugar de la template queremos mostrar ese componente. Y lo mismo para los otros 2.

Vamos a trabajar sobre esta parte:

  <div class="row my-4">
    <div class="col col-sm-10 col-md-8">
      <app-home></app-home>
    </div>
  </div>
  <div class="row my-4">
    <div class="col col-sm-10 col-md-8">
      <app-users></app-users>
    </div>
  </div>
  <div class="row">
    <div class="col col-sm-10 col-md-8">
      <app-servers></app-servers>
    </div>
  </div>

8. Para informar a Angular, nos deshacemos del segundo y cuarto row, quedándonos solo con el primero (+ su estructura de columnas).

9. Eliminamos todos los custom selectors y añadimos una directiva de Angular con aspecto de selector HTML: el router-outlet. ⛳ Esto es como poner un banderín que le indica a Angular dónde colocar un componente cuando su ruta sea seleccionada.

  <div class="row my-4">
    <div class="col col-sm-10 col-md-8">
      <router-outlet></router-outlet>
    </div>
  </div>

Si ahora guardamos y vamos a nuestro navegador, verás que los componentes han desaparecido. Todos, menos el HomeComponent, ya que esa es la ruta que queremos mostrar al iniciar nuestra app. Si desde tu barra de navegación escribes http://localhost:4200/users http://localhost:4200/servers, verás que se muestran esas 3 "páginas". 

homepage routing demo

http://localhost:4200

users demo routing

http://localhost:4200/users

servers demo routing app

http://localhost:4200/servers

¡Genial! Pero nuestros links de las pestañas aún no funcionan 🙈. Nos encargaremos de eso en la siguiente sección.

Navegación con Router Link

En el app.component.html, verás que los botones (<a>) tienen un atributo href. Con esta premisa, podríamos añadir ahí las rutas de esta manera:

        <li class="nav-item"><a class="nav-link active" href="/">Home</a></li>
        <li class="nav-item"><a class="nav-link" href="/servers">Servers</a></li>
        <li class="nav-item"><a class="nav-link" href="/users">Users</a></li>

Aunque esta técnica funcionaría, no es la recomendable por varios motivos. En primer lugar, porque ahora nuestra app se recarga cada vez que cambiamos de página. Fíjate en el icono de recarga cuando cambias de pestaña 🔄.

Esto, que en principio es el comportamiento por defecto de cualquier link cuando haces clic en él, no es lo ideal. Porque lo que ocurre es que, al hacer clic, estamos haciendo una petición (en inglés, request) al servidor para que nos devuelva algo (la ruta vinculada a un componente).

Ocurre lo mismo si escribimos el nombre de la ruta manualmente en la barra de navegación.

Esto significa que toda nuestra app se reinicia a cada clic, para luego re-dirigirse a la ruta seleccionada, lo cual, entre otras cosas, ralentiza la navegación, ofreciendo una mala experiencia de usuario (en inglés, user experience, o UX).

Como no podía ser de otra manera, Angular nos ofrece otro camino más eficiente, usando una de sus directivas: routerLinkVamos a ver cómo funciona 👀.

1. Nos deshacemos del atributo href y añadimos la directiva routerLink, que espera un stringEn el caso del link a la homepage, sólo necesitamos indicarle una barra ( / ), para que entienda que es un path vacío.

2. Vinculamos el routerLink con la ruta /servers en el botón de "Servers".

        <li class="nav-item"><a class="nav-link active" routerLink="/">Home</a></li>
        <li class="nav-item"><a class="nav-link" routerLink="/servers">Servers</a></li>

Otra forma de utilizar el routerLink es con property bindingpero en lugar de vincular la directiva a una propiedad, la vinculamos a un stringasí:

[routerLink]="'stringHere'"

O, mejor, a un array, así:

[routerLink]="[arrayHere]"

La opción del array es más flexible, ya que nos permite tener un mayor control sobre la directiva routerLink.

Los elementos del array serían los segmentos que componen un "path".

Por ejemplo, imaginemos que tenemos una página de perfil por cada usuario. Si navegamos hasta la página de perfil del usuario "Pepito", su ruta sería http://localhost:4200/users/pepito. Por tanto, podríamos crear un routerLink así:

[routerLink]="['/users', 'pepito']"

siendo '/users' 'pepito' los elementos del array.

🤓 Esta manera nos permite construir rutas complejas más fácilmente.

Sabiendo esto, configuramos el botón de Users con property binding, y añadimos únicamente un elemento al array (/users). De momento lo dejamos así, pero volveremos a esto más adelante.

   <li class="nav-item"><a class="nav-link" [routerLink]="['/users']">Users</a></li>

Si guardas y vas a tu navegador, verás que ahora el icono de recargar la página ya no cambia de estado, porque la página no se está recargando 👌. Esto es así porque el routerLink captura el clic hecho sobre el botón y previene el comportamiento por defecto de una etiqueta <a>, que sería mandar una petición al servidor. En lugar de eso, analiza lo que le pasamos entre las dobles comillas y busca si existe una ruta que coincida con alguna de las que le hemos indicado en el AppModule.

Router Link: Esquema

Captura el clic sobre el botón

Mejora la UX al aumentar la velocidad

Previene comportamiento default del botón

Evita pérdida de la application state

Diferencias entre un relative path y un absolute path

No es lo mismo escribir:

routerLink="/servers"

que:

routerLink="servers"

La barra importa, ya que determina si estamos indicando un path relativo (en inglés, relative) o absoluto (en inglés, absolute).

  • routerLink = "/ruta" 👉 absolute path 👉 no depende de la URL en la que nos encontremos
  • routerLink = "ruta" ðŸ‘‰ relative path 👉 depende de la URL en la que nos encontremos
    • escribir "ruta" o "./ruta" es lo mismo. Ojito con esto, no te hagas un lío 🧐. 

Si quitamos la barra de los paths de los botones Users Servers, verás que tu app funciona igual que antes.

<li class="nav-item"><a class="nav-link" routerLink="servers">Servers</a></li>
<li class="nav-item"><a class="nav-link" [routerLink]="['users']">Users</a></li>

Tanto en la barra de navegación como si te posicionas con el ratón encima de los botones, verás en la parte más baja de tu pantalla la ruta a la que te dirigirás cuando pinches. Pero en realidad, hay algo que ha cambiado 😮. Y es que ahora nuestros paths son relativos, lo que significa que serán añadidos al final de la URL en la que nos encontremos en ese momento 🤨.

Hagamos un ejemplo para entenderlo bien.

1. En el servers.component.html, creamos un botón con un routerLink servers, con un path relativo. El objetivo del botón es simplemente ir a la página en la que ya nos encontramos (la pestaña Servers). Coloca el botón donde quieras en la template.

    <a routerLink="servers">Keep me in the Servers page</a>

Si haces clic en él, verás que la consola te devuelve un error:

ERROR Error: Uncaught (in promise): Error: Cannot match any routes. URL Segment: 'servers/servers'

Y es que Angular está buscando una ruta que sea http://localhost:4200/servers/serversla cual, obviamente, no existe 😬. Si convertimos ese botón en un absolute path, el problema estaría solucionado.

    <a routerLink="/servers">Keep me in the Servers page</a>

Porque al ser un absolute path, lo que hay después de la barra se adjunta automáticamente a la URL con la que nuestra app se inicia, o sea, a  http://localhost:4200/ , creando así  http://localhost:4200/servers, ruta que sí existe.

Sin embargo, con los relative paths no ocurre lo mismo, ya que dependen de la URL en la que nos encontremos. Por eso se llaman "relativos", porque son rutas "relativas a algo". Ese "algo" es la ruta en la que nos encontremos.

Por esta razón los links del AppComponent siguen funcionando, porque están al nivel más alto posible (root) de nuestra app, donde el router no llega, ya que sólo lo hemos aplicado a los componentes que viven dentro del AppComponent. 

Así, los relative paths del AppComponent funcionan porque Angular siempre adjunta las dos rutas (servers users) a la URL http://localhost:4200/.

También podríamos navegar un nivel hacia arriba en el botón del ServersComponent, consiguiendo así generar la URL http://localhost:4200/servers, siendo ésta una ruta válida.

    <a routerLink="../servers">Keep me in the Servers page</a>

👩‍🏫 Usar relative paths tiene sentido cuando utilizamos rutas anidadas (en inglés, nested routes), pero nosotros aún no vamos a hacer ese uso avanzado. Por tanto, lo más conveniente a estas alturas es que usemos absolute paths. 

Así que eliminamos el botón del servers.component.html y dejamos los links del app.component.html como absolute paths.

       
<li class="nav-item"><a class="nav-link" routerLink="/servers">Servers</a></li>
        <li class="nav-item"><a class="nav-link" [routerLink]="['/users']">Users</a></li>


THE END!

¡Y con esto terminamos la 1ª parte de esta Guía completa sobre Routing! Aún nos queda mucho por aprender, como otras formas de usar los relative paths. Veremos eso y mucho más en la parte #2 (disponible próximamente). Por lo pronto, espero que hayas aprendido algo nuevo 😊.  Si te queda alguna duda, ¡nos vemos en los comentarios!

Más recursos de aprendizaje

En mi experiencia, la manera más eficaz para aprender Angular es combinando varias vías de aprendizaje. Uno de mis métodos favoritos son los vídeo-cursos y mi plataforma predilecta para eso es Udemy. He hecho varios cursos pero sólo recomiendo aquellos que verdaderamente me han sido útiles. Aquí van:


Si necesitas apoyo en forma de libro, puede que éstos te sirvan de ayuda:

La programación es un mundo que evoluciona a una velocidad de vértigo. Los autores de estos libros lo saben, por eso suelen encargarse de actualizar su contenido regularmente. Asegúrate de que así sea antes de adquirirlos 😌.

Participo en el programa de afiliados de Udemy y Amazon, lo que significa que, si compras alguno de estos cursos y/o libros, yo me llevaré una pequeña comisión y a ti no costará nada extra. Vamos, lo que se dice un win-win ðŸ˜Š.

Sobre la autora de este post

Soy Rocío, una abogada reconvertida en programadora. Soy una apasionada de aprender cosas nuevas y ferviente defensora de que la única manera de ser feliz es alcanzando un equilibrio entre lo que te encanta hacer y lo que te saque de pobre. Mi historia completa, aquí. 

Otros artículos que pueden interesarte

Días del 353 al 386
Objetivos versus realidad Y nuevamente, llegó otro día clave. Llegó…y pasó. El pasado 4 de marzo este Reto Computer Geek[...]
Construye Minioland: Tu primera aplicación con Angular | Parte #1
¿Qué vamos a construir?Minioland, o así he decidido llamar a esta sencilla app, totalmente responsive y de tipo Single Page[...]
Angular: Entendiendo la Directiva ngModel
Angular es un framework que nos permite, entre otras cosas, añadir contenido dinámico a nuestros archivos HTML. Una de las formas[...]
Si crees que este post puede serle útil a alguien, por favor, ¡compártelo!:

Deja un comentario

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.

Como toda web legal que se precie, utilizamos cookies para asegurar que damos la mejor experiencia al usuario en nuestro sitio web. Si continúas utilizando este sitio asumiremos que estás de acuerdo. más información

Los ajustes de cookies de esta web están configurados para "permitir cookies" y así ofrecerte la mejor experiencia de navegación posible. Si sigues utilizando esta web sin cambiar tus ajustes de cookies o haces clic en "Aceptar" estarás dando tu consentimiento a esto.

Cerrar