Reading query string parameters and configuring how Angular's router represents URLs are two separate routing concerns that come up early in most real Angular projects.
Reading query string parameters
constructor(private route: ActivatedRoute) {}
ngOnInit() {
this.route.queryParams.subscribe(params => {
this.page = params['page'] ? +params['page'] : 1;
this.sort = params['sort'] || 'newest';
});
}
Subscribing to queryParams (rather than reading it once as a snapshot) matters because Angular reuses the same component instance when only the query string changes on an otherwise identical route — without the subscription, navigating from ?page=1 to ?page=2 on the same component wouldn't trigger the component to react to the new value at all.
A one-time snapshot read, when reactivity isn't needed
const page = this.route.snapshot.queryParams['page'];
The snapshot approach is fine specifically when the component is guaranteed to be freshly created for each navigation (not reused across query-param-only changes) — reaching for the subscription-based approach by default is the safer general habit.
Updating query params without a full navigation
this.router.navigate([], {
relativeTo: this.route,
queryParams: { page: 2 },
queryParamsHandling: 'merge',
});
queryParamsHandling: 'merge' keeps any existing query params not explicitly overwritten — omitting it replaces the entire query string with only the params passed in this call.
The default hash-based URL style
https://example.com/#/products/42
By default, Angular can use hash-based routing (useHash: true), where everything after the # is handled entirely client-side and never sent to the server — this avoids needing any server-side URL rewrite configuration, which is why it's sometimes used for quick deployments.
Switching to path-based (HTML5) routing
RouterModule.forRoot(routes, { useHash: false }) // or simply omit useHash, false is the default
https://example.com/products/42
Path-based routing produces cleaner URLs without the #, but it requires the web server to be configured to redirect every route back to index.html — without that server-side rewrite rule, refreshing the browser on any route other than the root will 404, since the server has no actual file or route matching that path.
The Nginx rewrite rule needed for path-based routing
location / {
try_files $uri $uri/ /index.html;
}
The Apache equivalent (.htaccess)
RewriteEngine On
RewriteBase /
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.html [L]
Why this trips people up specifically on deployment
An Angular app using path-based routing works perfectly during local development (the Angular CLI's dev server already handles this fallback automatically) and then appears broken on every route except the homepage once deployed to a production server that isn't configured with the equivalent rewrite rule — this is one of the most common "it worked locally" surprises when deploying a new Angular app.