Cómo transferir datos en componentes enrutados de Angular: guía completa en TypeScript
\n\nCada desarrollador que comienza a trabajar con Angular, tarde o temprano se enfrenta a la pregunta: «¿Cómo transferir datos de un componente a otro a través del enrutador?». En Stack Overflow, esta pregunta ha acumulado miles de visitas, y no es casualidad. A diferencia de los componentes padre-hijo comunes, donde es suficiente usar @Input() y @Output(), el enrutamiento en Angular añade sus propias complejidades.
En este artículo, analizaremos 5 formas probadas de transferir datos en componentes enrutados de Angular. Aprenderá cuándo usar cada método y obtendrá ejemplos listos en TypeScript. ¡Vamos allá!
\n\n¿Por qué no se pueden transferir datos simplemente a través de @Input?
\n\nMuchos principiantes intentan hacer esto:
\n\n// ❌ Así no funciona\n<router-outlet [someData]="data"></router-outlet>\n\nEl enrutador de Angular crea componentes dinámicamente. router-outlet es una directiva, no un elemento de plantilla. Por lo tanto, la transferencia de datos directamente a través de atributos es imposible. Pero hay soluciones alternativas, ¡y son incluso más convenientes!
Método 1: Uso del Estado del Enrutador (el más simple)
\n\nLa forma más intuitiva es transferir datos a través del objeto state durante la navegación. Este método apareció en Angular 7+ y funciona «de fábrica».
Cómo funciona
\n\nUsted transfiere un objeto con datos al llamar a router.navigate() o a través de routerLink.
// Componente A — remitente\nimport { Component } from '@angular/core';\nimport { Router } from '@angular/router';\n\n@Component({\n selector: 'app-user-list',\n template: `\n <button (click)="goToDetails()">Abrir usuario</button>\n `\n})\nexport class UserListComponent {\n constructor(private router: Router) {}\n\n goToDetails() {\n this.router.navigate(['/user', 42], {\n state: { name: 'Iván Petrov', role: 'admin' }\n });\n }\n}\n\n// Componente B — receptor\nimport { Component, OnInit } from '@angular/core';\nimport { Router } from '@angular/router';\n\n@Component({\n selector: 'app-user-details',\n template: `\n <div *ngIf="userData">\n <h2>{{ userData.name }}</h2>\n <p>Rol: {{ userData.role }}</p>\n </div>\n `\n})\nexport class UserDetailsComponent implements OnInit {\n userData: any;\n\n constructor(private router: Router) {\n // Obtenemos los datos del historial de navegación\n this.userData = this.router.getCurrentNavigation()?.extras?.state;\n }\n\n ngOnInit() {\n // Forma alternativa — a través de history.state\n if (!this.userData) {\n this.userData = history.state;\n }\n }\n}\n\nVentajas y desventajas
\n- \n
- ✅ Simplicidad de implementación \n
- ✅ Los datos no son visibles en la URL \n
- ✅ Funciona con cualquier tipo de datos (objetos, arrays) \n
- ❌ Los datos se pierden al actualizar la página \n
- ❌ No funciona al navegar directamente por URL \n
Cuándo usarlo: para transferir datos temporales que no son críticos al recargar (por ejemplo, mensajes flash, filtros).
\n\nMétodo 2: Resolver de Ruta (para precarga de datos)
\n\nSi necesita cargar datos antes de que se muestre el componente, use un Resolver de Angular. Es un servicio que resuelve los datos antes de la activación de la ruta.
\n\nCreando un Resolver
\n\n// user.resolver.ts\nimport { Injectable } from '@angular/core';\nimport { Resolve, ActivatedRouteSnapshot } from '@angular/router';\nimport { Observable, of } from 'rxjs';\n\n@Injectable({ providedIn: 'root' })\nexport class UserResolver implements Resolve<any> {\n resolve(route: ActivatedRouteSnapshot): Observable<any> {\n const userId = route.paramMap.get('id');\n // Im