Skip to the solution
MediumFrontend9 min read

How do you read route parameters?

415 views

The problem

Question presented to candidate: "A user profile page lives at /users/:id, and it has a 'next user' button that navigates to /users/43 from /users/42. After clicking it, the page still shows user 42. Explain the ways to read route parameters in Angular, and what went wrong."

What a strong answer should cover:

  • Three sources: path parameters (:id), query parameters (?tab=posts) and matrix parameters (;mode=edit), plus static data and resolved data.
  • ActivatedRoute.snapshot.paramMap is a one-time read; ActivatedRoute.paramMap / queryParamMap are observables that emit on every change.
  • The router reuses the component when only parameters change, so a snapshot read in the constructor goes stale β€” the bug in the question.
  • Component input binding (withComponentInputBinding()): route values arrive as input()s by name and update on every navigation; a missing key is set to undefined.
  • Parameters are always strings (or null), so convert and validate them; parent parameters are inherited by child routes by default in Angular 22.

Clarifying questions expected:

  • "Is input binding enabled in this app, or are components reading ActivatedRoute directly?"
  • "Should the page reset its own state when the id changes, or keep it?"

Code / implementation expected: Yes β€” one component reading the same parameter three ways, navigated between ids.

  • routing
  • params

Try it yourself

Sketch your approach before you read the solution. That is what the interview tests.

Stuck? Get a hint.

A short nudge toward the approach. It will not give the answer away.

Solution

The solution is hidden so you can try first

9 min read Β· 10 sections

Read the code

AngularOne component reading :id via snapshot, paramMap and input binding
import { ApplicationConfig, Component, inject, input, signal } from "@angular/core";
import { toSignal } from "@angular/core/rxjs-interop";
import { ActivatedRoute, Router, RouterOutlet, provideRouter, withComponentInputBinding } from "@angular/router";
import { map } from "rxjs";

let created = 0;

@Component({
  selector: "app-user",
  template: `
    <p>snapshot id: {{ snapshotId }}</p>
    <p>paramMap id: {{ liveId() }}</p>
    <p>input id: {{ id() }} | tab: {{ tab() ?? "none" }} | section: {{ section() }}</p>
  `,
})
export class UserComponent {
  private route = inject(ActivatedRoute);

  // 1. Snapshot: read once. Goes stale if the router reuses this instance.
  snapshotId = this.route.snapshot.paramMap.get("id");

  // 2. Observable: emits every time the :id segment changes.
  liveId = toSignal(this.route.paramMap.pipe(map((p) => p.get("id"))));

  // 3. Component input binding (needs withComponentInputBinding()).
  //    Path params, query params, static data and resolved data all bind by name.
  id = input<string>();
  tab = input<string>();
  section = input<string>();

  constructor() {
    created++;
    console.log(`  UserComponent constructed (#${created}), snapshot id=${this.snapshotId}`);
  }
}

export const appConfig: ApplicationConfig = {
  providers: [
    provideRouter(
      [{ path: "users/:id", component: UserComponent, data: { section: "people" } }],
      withComponentInputBinding(),
    ),
  ],
};

@Component({
  selector: "app-root",
  imports: [RouterOutlet],
  template: `<router-outlet />`,
})
export class AppComponent {
  readonly router = inject(Router);
}

Discussion

Other approaches, follow-ups and how it went in real interviews.

Sign in to join the discussion.

No comments yet. Share how you would answer it.

Question 61 of 121 in Angular

Keep your momentum going.

Mark this question solved to track your progress, then take the next one while it is fresh.

All Angular questions
Up nextMedium

What is the difference between take(1) and first() operators in RxJS?

Continue