Angular Child Routes
Introduction
In Angular applications, as your app grows in complexity, you'll often need to organize your routes in a hierarchical structure. Child routes (also called nested routes) allow you to create parent-child relationships between routes, enabling you to build more complex UIs with nested components. This approach helps you create more modular and maintainable applications.
Child routes are particularly useful when you want to:
- Create a layout that has its own navigation system
- Organize related features within a section of your application
- Build a master-detail interface where a list and its detail views share a common layout
Understanding the Basics
In Angular's routing system, child routes are defined within a parent route configuration. The child components are then rendered inside the parent component's template using the <router-outlet>
directive.
Basic Structure
Here's how child routes are structured in Angular:
const routes: Routes = [
{
path: 'parent',
component: ParentComponent,
children: [
{ path: 'child1', component: Child1Component },
{ path: 'child2', component: Child2Component }
]
}
];
With this configuration:
/parent
will load theParentComponent
/parent/child1
will load theParentComponent
withChild1Component
nested inside it/parent/child2
will load theParentComponent
withChild2Component
nested inside it
Creating Your First Child Routes
Let's walk through a step-by-step example of implementing child routes in an Angular application.
Step 1: Set up the Components
First, let's create the necessary components:
ng generate component products
ng generate component products/product-list
ng generate component products/product-detail
Step 2: Configure the Routes
Next, set up the route configuration in your routing module:
// app-routing.module.ts
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { ProductsComponent } from './products/products.component';
import { ProductListComponent } from './products/product-list/product-list.component';
import { ProductDetailComponent } from './products/product-detail/product-detail.component';
const routes: Routes = [
{
path: 'products',
component: ProductsComponent,
children: [
{ path: '', component: ProductListComponent },
{ path: ':id', component: ProductDetailComponent }
]
}
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
Step 3: Setup the Parent Component Template
The parent component needs a <router-outlet>
to display its child components:
// products.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-products',
template: `
<div class="products-container">
<h2>Products Section</h2>
<div class="content">
<!-- Child components will be rendered here -->
<router-outlet></router-outlet>
</div>
</div>
`,
styleUrls: ['./products.component.css']
})
export class ProductsComponent { }
Step 4: Implement the Child Components
Now implement the child components:
// product-list.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-product-list',
template: `
<h3>Product List</h3>
<ul>
<li *ngFor="let product of products">
<a [routerLink]="['/products', product.id]">{{ product.name }}</a>
</li>
</ul>
`
})
export class ProductListComponent {
products = [
{ id: 1, name: 'Phone XL' },
{ id: 2, name: 'Phone Mini' },
{ id: 3, name: 'Phone Standard' }
];
}
// product-detail.component.ts
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
@Component({
selector: 'app-product-detail',
template: `
<div *ngIf="product">
<h3>Product Details</h3>
<p>ID: {{ product.id }}</p>
<p>Name: {{ product.name }}</p>
<button (click)="goBack()">Back to List</button>
</div>
`
})
export class ProductDetailComponent implements OnInit {
product: any;
constructor(private route: ActivatedRoute) {}
ngOnInit() {
const productId = this.route.snapshot.paramMap.get('id');
// In a real app, you would fetch the product from a service
this.product = {
id: productId,
name: `Product ${productId}`
};
}
goBack() {
window.history.back();
}
}
Navigating Between Child Routes
To navigate between child routes, you can use the routerLink
directive or the Router service:
Using RouterLink
<!-- For the product list -->
<a [routerLink]="['/products']">All Products</a>
<!-- For a specific product -->
<a [routerLink]="['/products', product.id]">{{ product.name }}</a>
Using Router Service
import { Router } from '@angular/router';
@Component({...})
export class SomeComponent {
constructor(private router: Router) {}
navigateToProductList() {
this.router.navigate(['/products']);
}
navigateToProductDetail(productId: number) {
this.router.navigate(['/products', productId]);
}
}
Advanced Child Routes Concepts
Multiple Router Outlets with Named Routes
You can have multiple router outlets in the same component by giving them different names:
// routing configuration
const routes: Routes = [
{
path: 'dashboard',
component: DashboardComponent,
children: [
{ path: 'stats', component: StatsComponent },
{
path: 'notifications',
component: NotificationsComponent,
outlet: 'sidebar'
}
]
}
];
<!-- In dashboard.component.html -->
<div class="main">
<router-outlet></router-outlet>
</div>
<div class="sidebar">
<router-outlet name="sidebar"></router-outlet>
</div>
Lazy Loading Child Routes
For larger applications, you can use lazy loading with child routes to improve performance:
// app-routing.module.ts
const routes: Routes = [
{
path: 'admin',
loadChildren: () => import('./admin/admin.module').then(m => m.AdminModule)
}
];
// admin-routing.module.ts
const routes: Routes = [
{
path: '',
component: AdminComponent,
children: [
{ path: 'dashboard', component: AdminDashboardComponent },
{ path: 'users', component: AdminUsersComponent }
]
}
];
Real-World Example: E-commerce Dashboard
Let's build a more comprehensive example of a dashboard with child routes:
Project Structure
app/
├── dashboard/
│ ├── dashboard.component.ts
│ ├── dashboard.component.html
│ ├── overview/
│ │ └── overview.component.ts
│ ├── sales/
│ │ └── sales.component.ts
│ └── inventory/
│ └── inventory.component.ts
└── app-routing.module.ts
Route Configuration
// app-routing.module.ts
const routes: Routes = [
{ path: '', redirectTo: '/dashboard', pathMatch: 'full' },
{
path: 'dashboard',
component: DashboardComponent,
children: [
{ path: '', redirectTo: 'overview', pathMatch: 'full' },
{ path: 'overview', component: OverviewComponent },
{ path: 'sales', component: SalesComponent },
{ path: 'inventory', component: InventoryComponent }
]
}
];
Dashboard Layout
<!-- dashboard.component.html -->
<div class="dashboard-container">
<div class="sidebar">
<h3>Dashboard Navigation</h3>
<nav>
<ul>
<li><a routerLink="overview" routerLinkActive="active">Overview</a></li>
<li><a routerLink="sales" routerLinkActive="active">Sales</a></li>
<li><a routerLink="inventory" routerLinkActive="active">Inventory</a></li>
</ul>
</nav>
</div>
<div class="content">
<router-outlet></router-outlet>
</div>
</div>
/* dashboard.component.css */
.dashboard-container {
display: flex;
height: 100%;
}
.sidebar {
width: 200px;
padding: 20px;
background-color: #f5f5f5;
}
.content {
flex: 1;
padding: 20px;
}
.active {
font-weight: bold;
color: #007bff;
}
This structure creates a dashboard with a persistent sidebar and different content areas that change based on the selected navigation item.
Common Issues and Solutions
Child Component Not Displaying
If your child component isn't displaying, check that:
- You've included a
<router-outlet>
in the parent component - The paths in your route configuration are correct
- The child route is properly registered under the
children
array of the parent route
Route Parameters in Child Routes
To access route parameters in a child route, you can use the ActivatedRoute
service:
import { ActivatedRoute } from '@angular/router';
@Component({...})
export class ChildComponent implements OnInit {
constructor(private route: ActivatedRoute) {}
ngOnInit() {
this.route.paramMap.subscribe(params => {
const id = params.get('id');
// use the id parameter
});
}
}
Summary
Child routes in Angular provide a powerful way to organize your application's UI into nested hierarchies. They allow you to:
- Create complex, multi-level navigation structures
- Keep related functionality grouped together
- Build modular interfaces with reusable layouts
- Improve the user experience with more intuitive navigation patterns
By understanding how to properly configure and implement child routes, you can build more maintainable and user-friendly Angular applications.
Additional Resources
- Official Angular Routing Documentation
- Angular Router: A Complete Example
- Child Routes and Component Reuse
Exercises
- Create a basic admin panel with child routes for "Users", "Settings", and "Reports" sections.
- Implement a master-detail view using child routes where clicking on an item in a list shows its details in a nested route.
- Build a multi-step form wizard using child routes where each step is a different route within a parent container.
- Extend the e-commerce dashboard example with additional features like route guards to protect certain child routes.
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)