Question
In an Angular 5.0.3 application, how can I read query parameters when the application starts with a URL such as:
/app?param1=hallo¶m2=123
I currently read parameters directly from the browser URL:
private getQueryParameter(key: string): string | null {
const parameters = new URLSearchParams(window.location.search);
return parameters.get(key);
}
However, I would like to use Angular's routing APIs instead. In the root component below, how can I access the query parameters in ngOnInit?
@Component({
selector: 'app-root',
template: '<router-outlet></router-outlet>'
})
export class AppComponent implements OnInit {
constructor(private route: ActivatedRoute) {}
ngOnInit(): void {
// Read query parameters here.
}
}
Short Answer
You will learn how Angular represents query parameters through ActivatedRoute, when to use a one-time snapshot, and when to subscribe so your component responds to URL changes. You will also see how to create URLs with query parameters through Angular's Router.
Concept
Query parameters are the optional key=value values after ? in a URL:
/app?param1=hallo¶m2=123
They are commonly used for data that describes a view without changing its route path: search text, page number, sort order, filters, and tracking values.
In Angular, query parameters belong to the router state. Inject ActivatedRoute into a routed component and read either:
route.snapshot.queryParamMapwhen you only need the value at component creation.route.queryParamMapwhen the value may change while Angular keeps the same component instance alive.
Unlike a path parameter such as /products/42, query parameters are not tied to one route segment. They are available from the active route, including a root-level AppComponent in a router-based application.
Use Angular's router APIs rather than manually parsing window.location.search. The router understands Angular navigation, works with route changes, and makes components easier to test.
Mental Model
Think of a route as the address of a building:
- The path is the street address:
/products/42. - Query parameters are notes attached to the address:
?tab=reviews&sort=newest.
ActivatedRoute is Angular's delivery slip for the current address. A snapshot is a photograph of the slip at one moment. An observable is a notification service that gives you a new slip whenever the query parameters change.
Syntax and Examples
Inject ActivatedRoute and use queryParamMap.
Read once with a snapshot
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
@Component({
selector: 'app-root',
template: '<router-outlet></router-outlet>'
})
export class AppComponent implements OnInit {
constructor(private route: ActivatedRoute) {}
ngOnInit(): void {
const param1 = this.route.snapshot.queryParamMap.get('param1');
const param2 = this.route.snapshot.queryParamMap.get('param2');
console.log(param1); // "hallo"
console.log(param2); // "123"
}
}
get() returns string | null, because the URL might not contain that parameter. URL values are always strings, so param2 is initially the string "123", not the number 123.
React to later changes
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
@Component({
selector: 'app-results',
template: '<p>Search: {{ searchTerm }}</p>'
})
export class ResultsComponent implements OnInit {
searchTerm = '';
constructor(private route: ActivatedRoute) {}
ngOnInit(): void {
this.route.queryParamMap.subscribe(params => {
this.searchTerm = params.get('q') || '';
});
}
}
When the URL changes from /results?q=angular to /results?q=router, the subscription runs again and updates searchTerm.
Older object-style API
Angular 5 also provides queryParams:
this.route.queryParams.subscribe(params => {
const param1 = params['param1'];
});
queryParamMap is usually clearer because it explicitly provides parameter access through get(), has(), and getAll().
Step by Step Execution
Consider this URL:
/results?q=angular&page=2
And this component:
ngOnInit(): void {
this.route.queryParamMap.subscribe(params => {
const query = params.get('q') || '';
const pageText = params.get('page') || '1';
const page = Number(pageText);
console.log(query, page);
});
}
Execution proceeds as follows:
- Angular creates
ResultsComponentfor the/resultsroute. - Angular injects the current
ActivatedRouteinto the constructor. ngOnInitsubscribes toqueryParamMap.- The router emits the current parameter map.
params.get('q')returns"angular".params.get('page')returns"2".Number("2")converts the URL string to the number2.- The console receives
angular 2.
If Angular later navigates to /results?q=typescript&page=3 without destroying the component, the observable emits again and repeats steps 5 through 8 with the new values.
Real World Use Cases
- Search pages:
/search?q=angularsupplies the text used to load results. - Pagination:
/orders?page=3&pageSize=25determines which records an API request should fetch. - Filtering:
/products?category=books&inStock=truerepresents selected filters. - Sorting:
/products?sort=price&direction=ascpreserves the user's ordering choice. - Tabs and display state:
/account?tab=securityopens a particular section. - Shareable views: A user can copy a filtered report URL and another user sees the same view.
Do not treat query parameters as trusted input. Validate values before using them in business logic or sending them to an API.
Real Codebase Usage
Production components typically normalize and validate query parameters before using them.
Use defaults and validate numbers
this.route.queryParamMap.subscribe(params => {
const requestedPage = Number(params.get('page') || '1');
this.page = Number.isInteger(requestedPage) && requestedPage > 0
? requestedPage
: 1;
});
This prevents values such as ?page=-2 or ?page=hello from breaking pagination.
Load data when parameters change
this.route.queryParamMap.subscribe(params => {
const search = params.get('q') || '';
this.productService.search(search).subscribe(products => {
this.products = products;
});
});
For rapidly changing parameters, such as a search field that updates the URL, real projects often use RxJS operators such as map, filter, debounceTime, distinctUntilChanged, and switchMap to avoid unnecessary requests.
Navigate through the Router
Create or update query parameters with Router, not by concatenating strings:
import { Router } from '@angular/router';
constructor(private router: Router) {}
showPage(page: number): void {
this.router.navigate(['/results'], {
queryParams: { q: 'angular', page: page }
});
}
To retain existing parameters while changing one value:
this.router.navigate([], {
queryParams: { page: 2 },
queryParamsHandling: 'merge'
});
In a component that is destroyed when navigation occurs, Angular normally cleans up route-observable subscriptions. If you subscribe to longer-lived observables or use a component that can persist, apply the project's standard unsubscribe pattern.
Common Mistakes
Expecting a number instead of a string
This URL parameter is text:
const page = this.route.snapshot.queryParamMap.get('page');
// page is "2", not 2
Convert and validate it:
const page = Number(this.route.snapshot.queryParamMap.get('page') || '1');
Forgetting that a parameter can be missing
Broken code:
const term = this.route.snapshot.queryParamMap.get('q');
console.log(term.toUpperCase());
get('q') can return null. Provide a fallback:
const term = this.route.snapshot.queryParamMap.get('q') || '';
console.log(term.toUpperCase());
Using a snapshot when the URL can change in place
A snapshot does not update after component creation:
const page = this.route.snapshot.queryParamMap.get('page');
Use queryParamMap.subscribe(...) if the same component must react to later query-parameter navigation.
Reading path parameters as query parameters
For /users/42, 42 is generally a path parameter, read with paramMap. For /users?id=42, id is a query parameter, read with queryParamMap.
Manually parsing window.location.search
new URLSearchParams(window.location.search)
This can work in a browser, but it bypasses Angular's router state and does not naturally react to router navigation. Prefer ActivatedRoute in Angular components.
Using the wrong route level
In nested routing, a route-specific path parameter may be on this.route.parent or a child route. Query parameters are shared across the current navigation, but organize route access in the component that owns the relevant view whenever possible.
Comparisons
| Need | Best API | Why |
|---|---|---|
| Read query parameters once at initialization | route.snapshot.queryParamMap | Simple one-time lookup |
| React when query parameters change | route.queryParamMap | Emits updated values |
Read /products/42 | route.paramMap | 42 is part of the path |
Read /products?page=2 | route.queryParamMap | page follows ? |
| Navigate with query parameters | router.navigate(..., { queryParams }) | Lets Angular construct the URL |
| Parse the browser URL manually | URLSearchParams | Usually unnecessary inside Angular routed components |
queryParams and queryParamMap both expose query parameters. queryParams provides a plain object, while queryParamMap provides methods such as get('key') and better communicates that a parameter may have multiple values.
Cheat Sheet
// Inject the active route
constructor(private route: ActivatedRoute) {}
// Read once
const value = this.route.snapshot.queryParamMap.get('key');
// React to changes
this.route.queryParamMap.subscribe(params => {
const value = params.get('key');
});
// Check for a value
const exists = this.route.snapshot.queryParamMap.has('key');
// Read repeated values
const tags = this.route.snapshot.queryParamMap.getAll('tag');
// Create a URL with query parameters
this.router.navigate(['/results'], {
queryParams: { q: 'angular', page: 2 }
});
// Keep existing query parameters while changing one
this.router.navigate([], {
queryParams: { page: 2 },
queryParamsHandling: 'merge'
});
Rules:
- Query parameters begin after
?and are separated by&. get()returnsstring | null.- Convert numeric and boolean-looking values yourself.
- Use a snapshot for a fixed initial value; use the observable for changes.
- Use
paramMapfor path parameters andqueryParamMapfor query parameters.
FAQ
How do I get query parameters in Angular 5?
Inject ActivatedRoute, then use this.route.snapshot.queryParamMap.get('name') for an initial value or subscribe to this.route.queryParamMap for updates.
Why does get('page') return a string?
All URL query parameter values are text. Convert the value with Number() or another validation function when you need a number.
What happens if the query parameter does not exist?
queryParamMap.get('name') returns null. Use a default, such as params.get('name') || ''.
Should I use queryParams or queryParamMap?
Both work in Angular 5. queryParamMap is often easier to read because it has explicit methods including get, has, and getAll.
Can AppComponent read query parameters?
Yes. Injecting ActivatedRoute into AppComponent can read query parameters. For route-specific screen logic, it is usually cleaner to read them in the routed page component.
How do I preserve query parameters during navigation?
Use queryParamsHandling: 'merge' in router.navigate() when you want to update some values while keeping existing ones.
Do query parameter changes recreate the component?
Not necessarily. Angular may reuse the same component for the same route path. Subscribe to queryParamMap if your component must update when only query parameters change.
Mini Project
Description
Build a small results page that reads q and page from the URL. The page displays the active search term and page number, and its buttons update the URL through Angular's router. This mirrors the URL-driven state used by search and catalog pages.
Goal
Create a results page that keeps its displayed search state synchronized with ?q=...&page=....
Requirements
Requirement 1
Keep learning
Related questions
@Directive vs @Component in Angular: Differences, Use Cases, and When to Use Each
Learn the difference between @Directive and @Component in Angular, including use cases, examples, and when to choose each.
Accessing Input Value from EventTarget in TypeScript
Learn why EventTarget has no value property in TypeScript and safely read values from HTML input events in Angular applications.
Angular (change) vs (ngModelChange): What’s the Difference?
Learn the difference between Angular (change) and (ngModelChange), when each fires, and which one to use in forms and inputs.