Routing is a core feature of Angular that allows developers to build single-page applications (SPAs) with multiple views without requiring a full page reload. By defining routes, Angular can dynamically load components based on the URL, creating seamless navigation experiences for users.
In this guide, we will explore Angular routing in depth—from basic setup to advanced topics such as lazy loading, route guards, parameterized routes, nested routing, and best practices.
What is Angular Routing?
Angular routing is the mechanism by which the URL path maps to a specific component. Instead of loading a new HTML page for each view, Angular dynamically loads the required component into a placeholder called a router-outlet
.
Benefits of Angular Routing
- Seamless SPA Navigation: No full-page reloads.
- Dynamic Component Loading: Only load the necessary component.
- Parameterized Routes: Pass data through URLs.
- Nested Views: Support for hierarchical routes and child components.
- Route Guards: Control access based on authentication or conditions.
- Lazy Loading: Load modules on demand to improve performance.
Setting Up Angular Routing
Step 1: Create an Angular Project
If you don’t already have a project:
ng new routing-app --routing
cd routing-app
ng serve
- The
--routing
flag automatically generatesapp-routing.module.ts
. - Serves the app at
http://localhost:4200
.
Step 2: Create Components
ng generate component home
ng generate component about
ng generate component contact
This will generate three components for our example routes.
Defining Routes
Routes are defined as an array of objects in the app-routing.module.ts
file.
Basic Route Definition
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { HomeComponent } from './home/home.component';
import { AboutComponent } from './about/about.component';
import { ContactComponent } from './contact/contact.component';
const routes: Routes = [
{ path: 'home', component: HomeComponent },
{ path: 'about', component: AboutComponent },
{ path: 'contact', component: ContactComponent },
{ path: '', redirectTo: '/home', pathMatch: 'full' }, // default route
{ path: '**', redirectTo: '/home' } // wildcard route
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
path
specifies the URL segment.component
specifies which component to display.redirectTo
redirects to another route.pathMatch: 'full'
ensures the entire URL matches.**
handles undefined routes.
Adding Navigation Links
Angular provides routerLink
for navigation in templates.
<nav>
<a routerLink="/home">Home</a>
<a routerLink="/about">About</a>
<a routerLink="/contact">Contact</a>
</nav>
<router-outlet></router-outlet>
routerLink
binds the anchor tag to a route.router-outlet
is the placeholder where the routed component will render.
Using Programmatic Navigation
Sometimes, you may want to navigate via code instead of template links.
import { Component } from '@angular/core';
import { Router } from '@angular/router';
@Component({
selector: 'app-home',
template: <button (click)="goToAbout()">Go to About</button>
})
export class HomeComponent {
constructor(private router: Router) {}
goToAbout() {
this.router.navigate(['/about']);
}
}
router.navigate(['/route'])
allows dynamic navigation.- You can also pass query parameters or route parameters.
Route Parameters
Routes can include dynamic parameters:
const routes: Routes = [
{ path: 'user/:id', component: UserComponent }
];
Accessing Route Parameters
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
@Component({
selector: 'app-user',
template: <p>User ID: {{ userId }}</p>
})
export class UserComponent implements OnInit {
userId!: string;
constructor(private route: ActivatedRoute) {}
ngOnInit() {
this.userId = this.route.snapshot.paramMap.get('id')!;
}
}
- Use
:id
in the route path. - Access the value with
ActivatedRoute
.
Query Parameters
Query parameters allow passing additional information:
<a [routerLink]="['/user', 1]" [queryParams]="{ref:'email'}">User 1</a>
In the component:
this.route.queryParams.subscribe(params => {
console.log(params['ref']); // Output: email
});
- Useful for filters, sorting, or optional data.
Child Routes and Nested Routing
Angular supports hierarchical routing with child routes.
const routes: Routes = [
{
path: 'dashboard',
component: DashboardComponent,
children: [
{ path: 'stats', component: StatsComponent },
{ path: 'reports', component: ReportsComponent }
]
}
];
Template for parent component:
<h2>Dashboard</h2>
<nav>
<a routerLink="stats">Stats</a>
<a routerLink="reports">Reports</a>
</nav>
<router-outlet></router-outlet>
- The nested router-outlet renders the child component.
Route Guards
Route guards control access to routes. Angular provides:
- CanActivate – prevent navigation to a route
- CanDeactivate – prevent leaving a route
- CanLoad – prevent lazy loading modules
Example: CanActivate Guard
import { Injectable } from '@angular/core';
import { CanActivate, Router } from '@angular/router';
@Injectable({
providedIn: 'root'
})
export class AuthGuard implements CanActivate {
isLoggedIn = false;
constructor(private router: Router) {}
canActivate(): boolean {
if (!this.isLoggedIn) {
this.router.navigate(['/home']);
return false;
}
return true;
}
}
- Attach the guard to a route:
{ path: 'profile', component: ProfileComponent, canActivate: [AuthGuard] }
Lazy Loading Modules
Lazy loading improves performance by loading modules only when needed.
const routes: Routes = [
{ path: 'admin', loadChildren: () => import('./admin/admin.module').then(m => m.AdminModule) }
];
- Angular automatically splits the bundle.
- Reduces initial load time for large apps.
Auxiliary Routes (Multiple Outlets)
Auxiliary routes allow multiple views simultaneously.
<router-outlet></router-outlet>
<router-outlet name="sidebar"></router-outlet>
Navigation:
this.router.navigate([{ outlets: { primary: ['home'], sidebar: ['chat'] } }]);
- Useful for modals, sidebars, or multi-pane layouts.
Router Events
Angular Router emits events that can be subscribed to:
import { Router, NavigationStart, NavigationEnd } from '@angular/router';
this.router.events.subscribe(event => {
if (event instanceof NavigationStart) console.log('Navigation started');
if (event instanceof NavigationEnd) console.log('Navigation ended');
});
- Useful for showing loading indicators or logging navigation.
Preloading Strategies
Angular supports preloading lazy modules to improve UX:
imports: [RouterModule.forRoot(routes, { preloadingStrategy: PreloadAllModules })]
PreloadAllModules
loads lazy modules in the background after initial load.
Router Animations
Angular allows animating route transitions:
import { trigger, transition, style, animate } from '@angular/animations';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
animations: [
trigger('routeAnimations', [
transition('* <=> *', [
style({ opacity: 0 }),
animate('300ms', style({ opacity: 1 }))
])
])
]
})
export class AppComponent {}
- Combine with
<router-outlet [@routeAnimations]="o.isActivated ? o.activatedRoute : ''"></router-outlet>
.
Common Routing Errors
- No route matches URL → Ensure routes are declared correctly.
- Router-outlet missing → Components cannot render without it.
- Incorrect pathMatch → Use
full
for default route. - Lazy load syntax errors → Always use dynamic imports:
import('./module').then(m => m.ModuleName)
.
Best Practices for Angular Routing
- Use feature modules for lazy loading.
- Group related routes under a module.
- Use route guards for secure access.
- Always define a wildcard route for 404 pages.
- Use child routes for nested views.
- Keep route paths simple and semantic.
- Combine query parameters and route parameters appropriately.
Leave a Reply