CodeForge

Angular 21 de Cero a Experto / Routing

Parámetros de ruta como señales

Teoría22 min20 XP

Una página de detalle necesita saber QUÉ mostrar: /gasto/5 muestra el gasto 5. Ese 5 es un parámetro de ruta, y Angular te lo entrega. La forma clásica era suscribirse a un Observable; la forma moderna —y hermosa— es recibir el parámetro directamente como un input() señal del componente, sin suscripciones. Hoy dominas ambas y entiendes por qué la nueva es un salto enorme.

El número de la habitación

Definir una ruta con parámetro

app.routes.ts
export const routes: Routes = [
{ path: '',           component: ListaGastosComponent },
{ path: 'gasto/:id',  component: DetalleGastoComponent },  // :id es un parámetro
];
// /gasto/5  → DetalleGastoComponent con id = "5"
// /gasto/8  → el mismo componente con id = "8"

Y enlazas a una ruta con parámetro pasando los segmentos:

link-param.ts
// enlace estático con el id interpolado
<a [routerLink]="['/gasto', g.id]">Ver {{ g.nombre }}</a>

// navegación por lógica
this.router.navigate(['/gasto', g.id]);

La forma moderna: el parámetro como input() señal

Angular 21 puede entregarte los parámetros de la URL directamente como INPUTS del componente. Activas la característica una vez y luego declaras un input() con el mismo nombre que el parámetro:

app.config.ts
import { provideRouter, withComponentInputBinding } from '@angular/router';

providers: [
provideRouter(routes, withComponentInputBinding()),   // ← activa el binding
];
detalle-gasto.component.ts
import { Component, input, computed, inject } from '@angular/core';
import { BolsilloStore } from './bolsillo.store';

@Component({
selector: 'app-detalle-gasto',
template: `
  @if (gasto()) {
    <h2>{{ gasto()!.nombre }}</h2>
    <p>{{ gasto()!.valor }} COP</p>
  } @else {
    <p>Gasto no encontrado.</p>
  }
`,
})
export class DetalleGastoComponent {
private store = inject(BolsilloStore);

// el parámetro ':id' de la URL llega como este input señal (string)
id = input.required<string>();

// deriva el gasto del id: cuando la URL cambia, 'id' cambia y esto se recalcula solo
gasto = computed(() => this.store.gastos().find((g) => g.id === Number(this.id())));
}

Esto es precioso: el parámetro de la URL es un input() señal, así que puedes DERIVAR de él con computed. Navegas de /gasto/5 a /gasto/8, el id cambia, y gasto se recalcula solo —el mismo componente, sin código de sincronización—.

Antes (subscribe a ActivatedRoute) vs Ahora (input signal)

Query params: configurar, no identificar

Los parámetros de ruta (:id) IDENTIFICAN un recurso; los query params (?categoria=comida) lo CONFIGURAN (filtros, orden, página). Se leen de forma parecida:

query.ts
// enlace con query params
<a [routerLink]="['/']" [queryParams]="{ categoria: 'comida', orden: 'valor' }">
Ver comida
</a>
// produce: /?categoria=comida&orden=valor

// leerlos (con el binding de inputs, un input del mismo nombre los recibe)
categoria = input<string>();   // ?categoria=comida  → 'comida'

Regla: si el dato define CUÁL recurso ves, es parámetro de ruta; si AJUSTA cómo lo ves, es query param. Filtros, búsqueda, orden y paginación → query params (así el estado del filtro vive en la URL y se puede compartir/marcar).

La lógica en vivo: derivar de un parámetro

El router no corre en el sandbox, pero la lógica —"del id de la URL, deriva el gasto"— es TS puro y reactivo. Simula el id como una señal que cambia al "navegar":

¿Qué ventaja tiene recibir el parámetro `:id` como `input()` señal frente a suscribirse a `ActivatedRoute.paramMap`?

Mini-reto

En el playground: 1) añade más gastos con distintos id; 2) crea un computed existe que sea true/false según si el gasto del idParam actual se encontró; 3) "navega" a varios ids con idParam.set(...) y observa cómo gasto y existe cambian solos. Luego escribe cómo se vería el componente Angular equivalente con input.required<string>() y su computed.

Qué sigue

Tus páginas ya reaccionan a la URL. Pero cargar TODO el código de todas las páginas al inicio es un desperdicio: el usuario quizá nunca abra las estadísticas. La próxima lección es el lazy loading —cargar cada página solo cuando se visita—, clave para que apps grandes arranquen rápido.