Skip to main content

Angular Route Parameters

In modern web applications, it's common to display dynamic content based on data from a server. Angular route parameters allow you to capture values from the URL and use them to fetch specific data or control what appears on the page. This feature is essential for building dynamic, data-driven applications.

What are Route Parameters?

Route parameters are segments in your URL path that change based on the specific content being displayed. For example, in a URL like /products/42, the "42" could be a route parameter representing a product ID.

Route parameters enable you to:

  • Display specific content based on IDs
  • Create dynamic, reusable components
  • Build clean URL structures for better SEO and user experience

Setting Up Route Parameters

Let's learn how to set up and access route parameters in your Angular application.

Step 1: Define Routes with Parameters

In your routing configuration, you can define parameters by prefixing them with a colon (:).

typescript
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { ProductListComponent } from './product-list/product-list.component';
import { ProductDetailComponent } from './product-detail/product-detail.component';

const routes: Routes = [
{ path: 'products', component: ProductListComponent },
{ path: 'products/:id', component: ProductDetailComponent }
];

@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }

In this example, :id is our route parameter. When a URL like /products/42 is accessed, the ProductDetailComponent will be loaded, and the value "42" will be available as the "id" parameter.

To navigate to routes with parameters, you can use the routerLink directive in your templates:

html
<div *ngFor="let product of products">
<a [routerLink]="['/products', product.id]">{{ product.name }}</a>
</div>

This creates links to individual product pages, passing the product ID as a route parameter.

Step 3: Accessing Route Parameters

There are two primary ways to access route parameters in your components:

Using ActivatedRoute with Snapshot

For components that won't change parameters during their lifetime:

typescript
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';

@Component({
selector: 'app-product-detail',
templateUrl: './product-detail.component.html',
styleUrls: ['./product-detail.component.css']
})
export class ProductDetailComponent implements OnInit {
productId: string;

constructor(private route: ActivatedRoute) { }

ngOnInit(): void {
// Access the route parameter using snapshot
this.productId = this.route.snapshot.paramMap.get('id');
console.log('Product ID:', this.productId);

// Use the ID to fetch product details from a service
// this.productService.getProductById(this.productId)...
}
}

Using ActivatedRoute with Observable

For components that may have their parameters change while the component remains active:

typescript
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, ParamMap } from '@angular/router';
import { switchMap } from 'rxjs/operators';
import { ProductService } from '../product.service';
import { Observable } from 'rxjs';
import { Product } from '../models/product.model';

@Component({
selector: 'app-product-detail',
template: `
<div *ngIf="product$ | async as product">
<h2>{{ product.name }}</h2>
<p>{{ product.description }}</p>
<p>Price: ${{ product.price }}</p>
</div>
`
})
export class ProductDetailComponent implements OnInit {
product$: Observable<Product>;

constructor(
private route: ActivatedRoute,
private productService: ProductService
) { }

ngOnInit(): void {
// React to parameter changes
this.product$ = this.route.paramMap.pipe(
switchMap((params: ParamMap) => {
const id = params.get('id');
return this.productService.getProductById(id);
})
);
}
}

The observable approach is particularly useful in scenarios where users might navigate between different items (like products) without leaving the component.

Multiple Route Parameters

You can define routes with multiple parameters:

typescript
// In your routing module
const routes: Routes = [
{ path: 'category/:categoryId/product/:productId', component: ProductDetailComponent }
];

And access them in your component:

typescript
ngOnInit(): void {
this.categoryId = this.route.snapshot.paramMap.get('categoryId');
this.productId = this.route.snapshot.paramMap.get('productId');

console.log('Category:', this.categoryId, 'Product:', this.productId);
}

Optional Route Parameters

Sometimes you may want parameters to be optional. While Angular doesn't have a direct syntax for optional path parameters, you can implement this pattern using query parameters or by defining multiple routes.

Real-world Example: Blog Post Viewer

Let's build a simple blog post viewer that uses route parameters to display specific posts:

First, define your routes:

typescript
const routes: Routes = [
{ path: 'blog', component: BlogListComponent },
{ path: 'blog/:postId', component: BlogPostComponent }
];

Create a service to fetch blog posts:

typescript
import { Injectable } from '@angular/core';
import { Observable, of } from 'rxjs';

export interface BlogPost {
id: string;
title: string;
content: string;
author: string;
date: string;
}

@Injectable({
providedIn: 'root'
})
export class BlogService {
private posts: BlogPost[] = [
{
id: '1',
title: 'Getting Started with Angular',
content: 'Angular is a platform for building mobile and desktop web applications...',
author: 'Alice Johnson',
date: '2023-05-15'
},
{
id: '2',
title: 'Understanding Angular Routing',
content: 'Routing in Angular allows you to navigate between different components...',
author: 'Bob Smith',
date: '2023-05-20'
},
// More posts...
];

getAllPosts(): Observable<BlogPost[]> {
return of(this.posts);
}

getPostById(id: string): Observable<BlogPost> {
const post = this.posts.find(p => p.id === id);
return of(post);
}
}

Implement the blog list component:

typescript
import { Component, OnInit } from '@angular/core';
import { BlogService, BlogPost } from '../blog.service';

@Component({
selector: 'app-blog-list',
template: `
<h1>Blog Posts</h1>
<div class="post-list">
<div *ngFor="let post of posts" class="post-preview">
<h2><a [routerLink]="['/blog', post.id]">{{ post.title }}</a></h2>
<p class="meta">By {{ post.author }} on {{ post.date }}</p>
</div>
</div>
`,
styles: [`
.post-list { max-width: 800px; margin: 0 auto; }
.post-preview { padding: 15px; border-bottom: 1px solid #eee; }
.meta { color: #666; font-style: italic; }
`]
})
export class BlogListComponent implements OnInit {
posts: BlogPost[] = [];

constructor(private blogService: BlogService) { }

ngOnInit(): void {
this.blogService.getAllPosts().subscribe(posts => {
this.posts = posts;
});
}
}

Now implement the blog post detail component that uses the route parameter:

typescript
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { BlogService, BlogPost } from '../blog.service';
import { switchMap } from 'rxjs/operators';
import { Observable } from 'rxjs';

@Component({
selector: 'app-blog-post',
template: `
<div *ngIf="post$ | async as post; else loading" class="post-container">
<a (click)="goBack()" class="back-link">← Back to all posts</a>
<h1>{{ post.title }}</h1>
<p class="meta">By {{ post.author }} on {{ post.date }}</p>
<div class="content">
{{ post.content }}
</div>
</div>
<ng-template #loading>Loading post...</ng-template>
`,
styles: [`
.post-container { max-width: 800px; margin: 20px auto; }
.back-link { cursor: pointer; color: blue; text-decoration: underline; }
.meta { color: #666; font-style: italic; }
.content { margin-top: 20px; line-height: 1.6; }
`]
})
export class BlogPostComponent implements OnInit {
post$: Observable<BlogPost>;

constructor(
private route: ActivatedRoute,
private router: Router,
private blogService: BlogService
) { }

ngOnInit(): void {
this.post$ = this.route.paramMap.pipe(
switchMap(params => {
const postId = params.get('postId');
return this.blogService.getPostById(postId);
})
);
}

goBack(): void {
this.router.navigate(['/blog']);
}
}

Handling Missing or Invalid Parameters

It's important to handle cases where a route parameter might not exist in your data:

typescript
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { ProductService } from '../product.service';
import { switchMap, catchError } from 'rxjs/operators';
import { of } from 'rxjs';

@Component({
// Component metadata
})
export class ProductDetailComponent implements OnInit {
product: any;
error: string = null;

constructor(
private route: ActivatedRoute,
private router: Router,
private productService: ProductService
) { }

ngOnInit(): void {
this.route.paramMap.pipe(
switchMap(params => {
const id = params.get('id');
return this.productService.getProductById(id).pipe(
catchError(error => {
this.error = `Product with ID ${id} not found`;
return of(null); // Return a null product
})
);
})
).subscribe(product => {
this.product = product;
if (!product && !this.error) {
// No product and no error means it wasn't found
this.router.navigate(['/products']); // Redirect to products list
}
});
}
}

Summary

Route parameters are a powerful feature of Angular's routing system that allow you to:

  • Create dynamic, data-driven applications
  • Pass information through the URL structure
  • Navigate between related content while maintaining context
  • Build clean, organized application architecture

By mastering route parameters, you can create more interactive and user-friendly web applications that respond to user needs with targeted content.

Additional Resources

Exercises

  1. Create a simple application that lists books and allows users to click on a book to view its details using route parameters.

  2. Extend the blog example to include categories, using multiple route parameters (e.g., /blog/:categoryId/:postId).

  3. Implement a user profile system where users can view their own profile at /profile and other users' profiles at /profile/:userId.

  4. Create a navigation breadcrumb system that uses route parameters to show the user's path through the application.

  5. Build an e-commerce product filtering system that uses route parameters to preserve filter states in the URL (e.g., /products/category/:categoryId/filter/:filterId).



If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)