Cómo usar parámetros de ruta y query params en Angular (con Signals e Inputs)

Al construir aplicaciones web modernas en Angular, pasar datos entre rutas y componentes es algo de todos los días. Aunque las librerías de manejo de estado y los servicios inyectables compartidos funcionan muy bien para el estado global, la URL suele ser la forma más limpia y fácil de compartir el estado de un componente.
Ya sea que necesites mostrar el perfil de un usuario por su ID (/user/123), filtrar un catálogo de productos con query parameters (/products?category=tech&discount=true), o delimitar parámetros con URLs de tipo matriz, el Router de Angular nos da varias herramientas prácticas para pasar y leer información.
En este artículo, vamos a revisar:
- Parámetros de ruta obligatorios (
:id) - Query parameters (
?key=value) - Parámetros de matriz (
;key=value) - Binding moderno con Signals usando
withComponentInputBinding()y signals de tipoinput()
Empecemos por entender cómo funcionan los parámetros obligatorios en las rutas.
1. Parámetros de ruta obligatorios (:id) 🎯
Los parámetros de ruta obligatorios forman parte del path de la URL. Puedes definir segmentos dinámicos en la configuración de tus rutas usando dos puntos (:):
export const routes: Routes = [
{
path: 'products/:id',
component: ProductDetailComponent
}
];Navegación hacia parámetros de ruta
Puedes navegar a rutas con parámetros dinámicos de forma declarativa con routerLink en tu plantilla, o de forma imperativa desde TypeScript usando el servicio Router.
En plantillas con routerLink:
<a [routerLink]="['/products', product.id]">
View {{ product.title }}
</a>De forma imperativa en TypeScript:
import { Component, inject } from '@angular/core';
import { Router } from '@angular/router';
@Component({
standalone: true,
selector: 'app-product-card',
template: `<button (click)="openProduct(123)">View Details</button>`
})
export class ProductCardComponent {
private readonly router = inject(Router);
openProduct(id: number) {
this.router.navigate(['/products', id]);
}
}La URL resultante se verá así:
https://danywalls.com/products/123Ahora que vimos cómo funcionan los parámetros en el path, veamos los query parameters opcionales.
2. Query Parameters (?key=value) 🔍
Los query parameters aparecen después del signo de interrogación (?) en la URL. Son ideales para filtros opcionales, paginación, términos de búsqueda o criterios de ordenamiento que no modifican la ruta principal.
Cómo pasar Query Parameters
En plantillas con [queryParams]:
<a [routerLink]="['/search']" [queryParams]="{ term: 'angular', page: 2 }">
Search Angular (Page 2)
</a>De forma imperativa con Router.navigate:
this.router.navigate(['/search'], {
queryParams: { term: 'angular', page: 2 },
queryParamsHandling: 'merge' // Mantiene los query params existentes si es necesario
});La URL resultante:
https://danywalls.com/search?term=angular&page=2El siguiente tipo de parámetro es menos común pero muy útil: los parámetros de matriz.
3. Parámetros de matriz (;key=value) 🧱
Los parámetros de matriz te permiten asociar pares clave-valor opcionales a un segmento específico de la URL, separados por punto y coma (;).
<!-- En plantillas -->
<a [routerLink]="['/products', { color: 'blue', size: 'medium' }]">
Filtered Products
</a>Navegación imperativa:
this.router.navigate(['/products', { color: 'blue', size: 'medium' }]);La URL resultante:
https://danywalls.com/products;color=blue;size=mediumAhora revisemos la forma más limpia y moderna de leer estos valores en Angular: el binding directo a inputs con Signals.
4. Binding moderno de rutas con Angular Signals ⚡
Históricamente, leer parámetros de la URL requería suscribirse a los observables paramMap o queryParamMap de ActivatedRoute y gestionar las suscripciones manualmente.
En el Angular moderno, puedes vincular los parámetros de ruta directamente a los inputs de tu componente de forma automática usando withComponentInputBinding().
Paso 1: Habilitar withComponentInputBinding en app.config.ts
import { ApplicationConfig } from '@angular/core';
import { provideRouter, withComponentInputBinding } from '@angular/router';
import { routes } from './app.routes';
export const appConfig: ApplicationConfig = {
providers: [
provideRouter(
routes,
withComponentInputBinding() // 👈 Habilita el binding automático de inputs
)
]
};Paso 2: Leer parámetros de ruta y Query Params usando input() con Signals
Una vez habilitado, cualquier parámetro de ruta, query parameter o dato resuelto en el router para esa ruta se inyecta directamente en las propiedades @Input o input() coincidentes de tu componente:
import { Component, input, computed, inject } from '@angular/core';
import { ProductsService } from '../services/products.service';
@Component({
standalone: true,
selector: 'app-product-details',
template: `
@if (selectedProduct(); as product) {
<article class="product-detail">
<h2>{{ product.title }}</h2>
<p>{{ product.description }}</p>
<span class="price">\${{ product.price }}</span>
@if (discount()) {
<div class="badge">Special 10% Discount Applied!</div>
}
</article>
}
`
})
export class ProductDetailsComponent {
private readonly productService = inject(ProductsService);
// 1. Coincide con la ruta ':id', inyectado como Signal de forma automática
readonly id = input.required<string>();
// 2. Coincide con el query param '?discount=true', inyectado automáticamente
readonly discount = input<string>();
// 3. Signal computado reactivo que se recalcula cuando 'id' cambia
readonly selectedProduct = computed(() => {
const products = this.productService.products();
return products.find(p => p.id === this.id());
});
}Ventajas principales de usar Signal Input Binding:
- Menos código repetitivo: No necesitas inyectar
ActivatedRouteni gestionar suscripciones de RxJS. - Reactividad limpia: Cuando el parámetro de la URL cambia (por ejemplo, el usuario pasa de
/products/1a/products/2), el signalid()se actualiza de forma automática, activando los signals computados y refrescando la plantilla. - Seguridad de tipos: Funciona de forma transparente con
input.required<string>()y funciones de transformación.
5. Alternativa: Leer parámetros con ActivatedRoute y toSignal 🔄
Si necesitas acceso a todo el estado de ActivatedRoute o quieres crear signals derivados a partir de queryParamMap dentro de un servicio:
import { Injectable, inject } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { toSignal } from '@angular/core/rxjs-interop';
import { map } from 'rxjs';
@Injectable({ providedIn: 'root' })
export class SearchStateService {
private readonly route = inject(ActivatedRoute);
// Convierte el observable queryParamMap en un Signal reactivo
readonly searchTerm = toSignal(
this.route.queryParamMap.pipe(
map(params => params.get('q') ?? '')
),
{ initialValue: '' }
);
}Para tener una referencia rápida de cuándo usar cada uno, preparemos una tabla comparativa.
Tabla comparativa de parámetros 📊
| Tipo de parámetro | Ejemplo de sintaxis URL | ¿Requiere definirlo en la ruta? | Cuándo usarlo |
|---|---|---|---|
| Parámetro de ruta | /products/123 | ✅ Sí (:id) | Identificadores clave de entidades, rutas RESTful |
| Query Param | /products?category=shoes | ❌ No | Filtros, búsquedas, paginación, flags opcionales |
| Parámetro de matriz | /products;size=large | ❌ No | Parámetros específicos en segmentos intermedios |
Resumen 🛠️
Manejar el estado de la URL en Angular hoy en día es mucho más limpio y directo:
- Usa
provideRouter(routes, withComponentInputBinding())para pasar datos de la ruta a los inputs del componente de forma automática. - Usa signals de tipo
input()ycomputed()para manejar cambios de parámetros de forma reactiva sin tener que gestionar suscripciones manuales. - Usa
[queryParams]para filtros opcionales y estado que los usuarios puedan guardar o compartir en sus marcadores.
Si quieres conocer más patrones modernos de arquitectura en Angular, te invito a leer mis artículos sobre Cómo usar ng-template, ng-container y ng-content en Angular y Cómo compartir datos entre componentes en Angular.
These are my experiences learning and facing my daily challenges working with Angular.
Preguntas Frecuentes
¿Cuál es la diferencia entre los parámetros de ruta y los query params en Angular?
Los parámetros de ruta (por ejemplo, /products/:id) son segmentos dinámicos obligatorios definidos directamente en la ruta. Los query params (por ejemplo, /products?category=shoes&page=2) van después del símbolo '?', son opcionales y no requieren registrarse en la configuración de rutas.
¿Cómo vinculo los parámetros de ruta directamente a los inputs de un componente en Angular?
En la configuración de tu aplicación, activa 'withComponentInputBinding()' dentro de 'provideRouter(routes, withComponentInputBinding())'. Luego, en tu componente, declara un input signal con el mismo nombre (por ejemplo, id = input<string>()). Angular vinculará automáticamente el parámetro de la URL con el input signal.
¿Cómo leo query params de forma reactiva usando Signals en Angular?
Puedes inyectar 'ActivatedRoute' y convertir su observable 'queryParamMap' en un Signal reactivo usando el helper 'toSignal()' de '@angular/core/rxjs-interop', o recibir los query params como inputs al activar 'withComponentInputBinding()'.
¿Qué son los parámetros de matriz en el enrutamiento de Angular?
Los parámetros de matriz son pares clave-valor separados por punto y coma (por ejemplo, /products;color=red;size=large) asociados a un segmento específico de la URL. Sirven para acotar un estado opcional a una jerarquía de ruta concreta sin ensuciar los query strings globales.
Artículos Relacionados
Cómo usar ng-template, ng-container y ng-content en Angular (Guía completa)
Aprende las diferencias exactas entre ng-template, ng-container y ng-content en Angular, cómo pasar contexto con ngTemplateOutlet, proyección con múltiples slots y cómo evolucionan con el control flow moderno de @if, @for y @defer.
Cómo compartir datos entre componentes en Angular (Signals y servicios)
Aprende los mejores patrones para compartir datos entre componentes en Angular. Compara los decoradores clásicos Input/Output y BehaviorSubjects con las Signals modernas: input(), output(), model() y servicios basados en Signals.
Cómo integrar scripts y CSS de terceros en tu aplicación Angular
Aprende a integrar librerías de JavaScript, hojas de estilo CSS y Web Components de terceros en Angular con bundles en angular.json, carga dinámica de scripts y afterNextRender seguro para SSR.
Compartir este artículo
Si esta guía te resultó útil, compártela con tu equipo o con otros desarrolladores.
Software real. Lecciones reales.
Comparto las lecciones que aprendí por las malas, para que puedas evitarlas o estar preparado cuando ocurran.
Únete a 13,800+ desarrolladores y lectores.
Cero spam. Cancela tu suscripción en cualquier momento.