100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
TypeScript

Route Parameters and Query Params

Understand how to pass dynamic data through the URL using required route parameters and optional query parameters, and how to read them reactively in a component.

Routing with the Angular RouterBeginner9 min readJul 9, 2026
Analogies

Route Parameters and Query Params

Real applications rarely have a fixed, finite set of pages — a product catalog needs one route that works for thousands of products, and a search page needs to reflect filters in the URL so results are shareable and bookmarkable. Angular's router supports this through two complementary mechanisms: route (path) parameters, which are required segments embedded directly in the URL path and identified with a colon prefix like :id, and query parameters, which are optional key-value pairs appended after a ? and are independent of route matching. Both are readable from the injected ActivatedRoute service, either as static snapshots or as reactive observables that update when the same component instance is reused for a new parameter value.

🏏

Cricket analogy: Route params versus query params are like a stadium gate number that's required to find your seat block (:id in the path) versus optional add-ons like a parking pass or programme (?parking=true) that don't affect which gate you use.

Defining and Reading Route Parameters

A route parameter is declared in the path string itself, e.g. { path: 'products/:id', component: ProductDetailComponent }. When the URL is /products/42, Angular matches this route and makes id: '42' available. Because Angular reuses component instances by default when navigating between two URLs that match the same route (e.g. /products/42 to /products/43), reading the parameter only once in ngOnInit via a snapshot will miss subsequent changes — the component won't be destroyed and recreated. For that reason, the recommended approach is to subscribe to ActivatedRoute.paramMap, an observable that emits a new ParamMap every time the parameters change.

🏏

Cricket analogy: Angular reusing the component instance between /products/42 and /products/43 is like a commentary booth staying staffed by the same commentator across consecutive overs of the same match rather than being replaced each over, so they must actively watch for the new ball rather than assuming nothing changed.

typescript
import { Component, inject, signal } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { toSignal } from '@angular/core/rxjs-interop';
import { map, switchMap } from 'rxjs/operators';
import { ProductService } from './product.service';

@Component({
  selector: 'app-product-detail',
  standalone: true,
  template: `
    @if (product(); as p) {
      <h2>{{ p.name }}</h2>
      <p>Price: {{ p.price | currency }}</p>
    } @else {
      <p>Loading product...</p>
    }
  `,
})
export class ProductDetailComponent {
  private route = inject(ActivatedRoute);
  private productService = inject(ProductService);

  // paramMap$ -> id -> product, converted to a signal for the template
  product = toSignal(
    this.route.paramMap.pipe(
      map((params) => params.get('id')!),
      switchMap((id) => this.productService.getById(id))
    )
  );
}

Query Parameters

Query parameters are not declared in the route path at all — any route can receive any query params. They're ideal for optional, non-hierarchical state such as pagination (?page=2), sorting (?sort=price), or search filters (?category=books&inStock=true). You read them via ActivatedRoute.queryParamMap, which behaves like paramMap but for the query string, and you set them either through routerLink's [queryParams] input or by passing a queryParams option to router.navigate().

🏏

Cricket analogy: Query params for sorting and filtering are like a scorecard app letting you append ?sort=runs&format=t20 to any match URL without changing which match page you're on, purely adjusting how the stats are displayed.

typescript
// Template: link that adds/updates query params without changing the path
// <a [routerLink]="['/products']" [queryParams]="{ category: 'books', page: 2 }">Books, page 2</a>

import { Component, inject } from '@angular/core';
import { Router, ActivatedRoute } from '@angular/router';

@Component({ selector: 'app-filters', standalone: true, template: `...` })
export class FiltersComponent {
  private router = inject(Router);
  private route = inject(ActivatedRoute);

  applyFilter(category: string): void {
    this.router.navigate([], {
      relativeTo: this.route,
      queryParams: { category },
      queryParamsHandling: 'merge', // keep existing params like 'page'
    });
  }
}

queryParamsHandling: 'merge' is a subtle but important option — without it, navigating with new queryParams replaces the entire query string, silently discarding unrelated params like pagination or sort order that the user had already set.

Subscribing to paramMap or queryParamMap manually with .subscribe() creates an Observable subscription that must be unsubscribed in ngOnDestroy to avoid memory leaks — unless you use the async pipe in the template or toSignal(), both of which handle cleanup automatically.

  • Route parameters (:id) are required, path-embedded values declared in the route's path string.
  • Query parameters are optional key-value pairs after ?, independent of route matching, ideal for filters/pagination.
  • Use ActivatedRoute.paramMap / queryParamMap observables rather than one-time snapshots, since Angular reuses component instances.
  • toSignal() or the async pipe convert these observables into template-friendly values with automatic unsubscription.
  • Use queryParamsHandling: 'merge' to update one query param without wiping out the others.
  • Static snapshots (route.snapshot.paramMap) only reflect the params at initial load, missing later in-place navigations.

Practice what you learned

Was this page helpful?

Topics covered

#TypeScript#AngularStudyNotes#WebDevelopment#RouteParametersAndQueryParams#Route#Parameters#Query#Params#SQL#StudyNotes#SkillVeris