🇺🇸 EN
Angular
·6 min read·↗·🇺🇸 EN

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

Portada principal del artículo: 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:

  1. Parámetros de ruta obligatorios (:id)
  2. Query parameters (?key=value)
  3. Parámetros de matriz (;key=value)
  4. Binding moderno con Signals usando withComponentInputBinding() y signals de tipo input()

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 
  }
];

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.

<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/123

Ahora 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=2

El 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=medium

Ahora 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:

  1. Menos código repetitivo: No necesitas inyectar ActivatedRoute ni gestionar suscripciones de RxJS.
  2. Reactividad limpia: Cuando el parámetro de la URL cambia (por ejemplo, el usuario pasa de /products/1 a /products/2), el signal id() se actualiza de forma automática, activando los signals computados y refrescando la plantilla.
  3. 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ámetroEjemplo 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❌ NoFiltros, búsquedas, paginación, flags opcionales
Parámetro de matriz/products;size=large❌ NoPará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() y computed() 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.

Parte de la serie Angular

These are my experiences learning and facing my daily challenges working with Angular.

Ver serie completa

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

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.

User avatar
User avatar
User avatar
User avatar
+13K

Únete a 13,800+ desarrolladores y lectores.

Cero spam. Cancela tu suscripción en cualquier momento.