Última actualización: 1 diciembre, 2020
Ya hemos visto cómo registrar y cargar rutas para mostrar varias páginas usando únicamente un archivo HTML en lugar de varios, gracias a la magia del Router que forma parte de Angular. También vimos cómo navegar usando rutas relativas (en inglés, relative paths) y absolutas (en inglés, absolute paths) y cómo aplicarles parámetros para crear rutas dinámicas. Continuemos por ese camino.
Cómo obtener parámetros de una ruta
Vamos a simular que alguien quiere acceder a la información del usuario "Jamie" (uno de los users que hemos escrito en el código TypeScript estáticamente). Primero, vamos a escribir manualmente la ruta que queremos simular. Por ejemplo http://localhost:4200/users/1/jamie.
Para ello, lo que haremos será cargar el UserComponent. Una vez cargado, la URL contendrá datos a los que queremos acceder para poder mostrar efectivamente el UserComponent con los parámetros que le hayamos pedido. Es decir, en lugar de mostrar:
User with ID _ID_ loaded.
User name is _NAME_
que se muestre:
User with ID 1 loaded.
User name is Jamie
Obtendremos el acceso desde el archivo TypeScript (en adelante, TS) del UserComponent.
1. Inyectamos el ActivatedRoute y lo convertimos en propiedad, bautizándolo como route. Recuerda que esta es la forma de acceder a la ruta que esté actualmente activa.
Tenemos una propiedad, user, a la que todavía no le hemos dado uso. Es el momento de hacerlo. A través de ella y del ActivatedRoute podemos acceder a los datos de la URL y rescatarlos (en inglés, fetch). Hacemos esta operación cuando nuestro componente se inicializa, es decir, en el ngOnInit.
Para acceder a los valores del objeto user (id y name), utilizamos una propiedad del ActivatedRoute: snapshot, a través de la cual accedemos a params, y ahí le pasamos el que queramos rescatar. Empecemos con el id.
constructor(private route: ActivatedRoute) { } ngOnInit() { this.user = { id: this.route.snapshot.params['id'], name: }; }
Como verás, el user object espera dos propiedades (id y name). Estas propiedades las rescatará de lo que hayamos definido en nuestros parámetros de la ruta. Es decir, del app.module.ts:
{ path: 'users/:id', component: UserComponent },
Ahí tenemos definido solo un segmento (el id), pero no el name . Vamos a solucionar eso.
{ path: 'users/:id/:name', component: UserComponent },
Con esto, ya podemos rescatar también el name desde el user.component.ts.
name: this.route.snapshot.params['name']
Podemos añadir todos los parámetros que queramos y rescatarlos de esta manera.
2. Vamos al user.component.html y añadimos los datos del usuario con string interpolation.
Si ahora vas a tu navegador e insertas una URL tipo http://localhost:4200/users/3/Jamie, verás que se te muestra un usuario con esos datos:
Es más, funciona con cualquier dato . Prueba a poner el número o el nombre que quieras. Como ves, esto no es ideal, y nos encargaremos de arreglarlo más adelante.
Cómo obtener parámetros de una ruta de manera reactiva
En ocasiones, el enfoque utilizado en el apartado anterior no nos será útil. Pongamos un ejemplo.
1. En las dev tools, activamos la memoria caché.
2. En el user.component.html, añadimos un link (que simulará llevarnos al perfil de un usuario) con routerLink incorporado.
3. Lo vinculamos a users con un absolute path con property binding y como segundo segmento le pasamos un número, que actuará como ID. Como tercero le pasamos un nombre, el que queramos también. Esto construirá un ruta que será algo así: http://localhost:4200/users/8/john.
Si guardas y vas a tu navegador, verás que pulsando en el botón "John profile", la URL se actualiza, pero la UI no .
Este es el comportamiento por defecto de Angular, y de hecho, a veces ocurrirá aunque la caché esté desactivada. El motivo por el ocurre esto es porque, para empezar, estamos cargando nuestros datos utilizando la propiedad snapshot en la ruta. Pero esto sólo ocurre la primera vez que instanciamos el UserComponent.
Por tanto, cuando ya nos encontramos en el UserComponent e intentamos ir al "perfil de John" pulsando en el botón, Angular no vuelve a instanciar el componente, porque sabe que no hace falta, ya que detecta que ya ha sido instanciado .
Es cierto que la información del componente ha cambiado al hacer click en el botón "John profile", pero Angular no tiene ni idea de que eso ha ocurrido, porque, ¿cómo se iba a enterar? Nadie se lo ha dicho...y de momento, Angular no es adivino .
Por otro lado, aún suponiendo que Angular se diese cuenta mágicamente que algo ha cambiado en el componente, eso tampoco sería razón para destruirlo y volver a instanciarlo de nuevo, ya que esto supondría un coste a nivel de performance.
Breve introducción al mundo de los Observables
Utilizar la configuración del snapshot para acceder a la URL en el momento en que el componente se instancia está bien, pero sólo para ese momento. Para todos los cambios que ocurran a posteriori, debemos aplicar otra técnica. Una técnica que permitirá a nuestro código reaccionar a todos los cambios que sucedan después de la inicialización del componente.
Y es que a través de ActivatedRoute podemos acceder a una propiedad llamada params, que nada tiene que ver con la propiedad params del snapshot, porque el params del ActivatedRoute es un Observable.
Los Observables son una característica que incorpora Angular (indirectamente, a través de una tercera parte, un paquete llamado rxjs) que nos facilita trabajar con tareas asíncronas.
El caso que nos ocupa (la tarea de hacer click sobre el botón "John profile" y que la URL cambie) es un caso de tarea asíncrona, ya que no existe manera de saber cuándo el usuario hará click sobre el botón, si es que lo hace en algún momento. Por tanto, no tendría sentido paralizar nuestro código y sentarnos a esperar a que el click suceda .
Un Observable nos hace esta tarea muy fácil, ya que él solito "observa" en todo momento si cierto evento ocurre, discretamente, sin afectar a la performance de tu app. Si llega el momento en que el evento que estabas esperando sucede (alguien hace click en el botón "John profile"), el Observable nos avisa, ejecutando automáticamente el código vinculado al click del botón.
Esa manera de "observar" de un Observable se llama "suscribirse a algo" (en inglés, subscribe). Para mí, un Observable es como suscribirse a Netflix . Ya no necesitas estar continuamente buscando cuándo sale el siguiente episodio de Outlander: Netflix te avisa cuando éste está disponible y mientras, tú puedes dedicarte a otras cosas.
Para poder reaccionar a cambios que ocurran después de la inicialización de un componente, debemos usar un Observable.
1. Dentro del ngOnInit, accedemos al Observable "params" del router object y nos suscribimos a él usando el método subscribe.
El método subscribe acepta tres argumentos en forma de funciones, siendo el primero el más importante. El primer argumento se dispara cuando el Observable detecta nueva información al haberse producido alguna actividad. Por ejemplo, cuando la URL cambie.
2. Le pasamos como primer argumento una función que acepta como argumento los parámetros actualizados, que será de tipo Params. Dentro de la función, actualizamos las propiedades del user object, dándole los valores que recibiremos en el argumento.
this.route.params .subscribe( (updatedParams) => { this.user.id = updatedParams['id']; this.user.name = updatedParams['name']; } );
¡Y listo! Ahora el botón "John profile" ya activa su funcionalidad y la UI se actualiza correctamente.
Este enfoque es el que siempre deberíamos tomar para asegurarnos de que los cambios que sucedan después de la inicialización se reflejen en la template del componente y por tanto, en la UI .
Pequeña advertencia sobre la vida de un Observable
Podríamos dejar la configuración de nuestro Observable tal y como está y estaría bien, completa. Pero únicamente porque entre bambalinas,
Angular se encargará de limpiar la suscripción al Observable cuando ya no usemos el componente (es decir, cuando se ejecute el ngOnDestroy).
O lo que es lo mismo, se desuscribirá (en inglés, unsubscribe) por nosotros.
Si Angular no hiciese esto por defecto, al salirnos del componente la suscripción se quedaría almacenada en alguna parte de la memoria de la app. En el momento en que volviésemos a entrar al componente, un nueva versión del componente se inicializaría y esto ocasionaría un caos .
Cuando creemos nuestros propios Observables (más adelante) tendremos que desuscribirnos de ellos manualmente, ya que Angular sólo hace la desuscripción automática con los que trae por defecto, como params. Así que aunque no sea necesario, vamos a aprender a desuscribirnos de estos Observables de Angular.
1. Importamos la interface OnDestroy.
2. Creamos una propiedad para almacenar la suscripción, llamada paramsSubscription, por ejemplo. Debe ser de tipo Subscription.
3. Guardamos el Observable dentro de la propiedad paramsSubscription.
4. Implementamos el método ngOnDestroy, desuscribiéndonos del Observable usando el método unsubscribe.
Y esto es lo que ya hace Angular por nosotros en este caso, pero es conveniente que sepamos cómo lo hace, así que podemos borrarlo, aunque yo lo voy a dejar ahí de referencia .
import { Component, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { Subscription } from 'rxjs'; @Component({ selector: 'app-user', templateUrl: './user.component.html', styleUrls: ['./user.component.css'] }) export class UserComponent implements OnInit, OnDestroy { user: { id: number, name: string }; paramsSubscription: Subscription; constructor(private route: ActivatedRoute) { } ngOnInit() { this.user = { id: this.route.snapshot.params['id'], name: this.route.snapshot.params['name'] } this.paramsSubscription = this.route.params .subscribe( (updatedParams) => { this.user.id = updatedParams['id']; this.user.name = updatedParams['name']; } ); } ngOnDestroy() { this.paramsSubscription.unsubscribe(); } }
¡FIN DE LA PARTE #3!
Espero que hayas aprendido algo nuevo . Si te queda alguna duda, ¡nos vemos en los comentarios! Y si quieres seguir aprendiendo, nos vemos en la parte #4.
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í.
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 .
Otros artículos que pueden interesarte