Angular Routing & Navigation
Angular Router enables navigation from one view to the next as users perform tasks. It interprets browser URLs and navigates to client-generated views.
Router Setup
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { HomeComponent } from './home/home.component';
import { AboutComponent } from './about/about.component';
import { UserListComponent } from './users/user-list.component';
import { UserDetailComponent } from './users/user-detail.component';
import { NotFoundComponent } from './not-found/not-found.component';
const routes: Routes = [
{ path: '', redirectTo: '/home', pathMatch: 'full' },
{ path: 'home', component: HomeComponent },
{ path: 'about', component: AboutComponent },
{
path: 'users',
component: UserListComponent,
children: [
{ path: ':id', component: UserDetailComponent }
]
},
{ path: '**', component: NotFoundComponent } // Wildcard route
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
// Standalone app setup
import { provideRouter } from '@angular/router';
import { bootstrapApplication } from '@angular/platform-browser';
bootstrapApplication(AppComponent, {
providers: [
provideRouter(routes)
]
});Navigation
import { Component } from '@angular/core';
import { Router, ActivatedRoute } from '@angular/router';
@Component({
selector: 'app-nav',
template: `
<!-- Declarative navigation -->
<nav>
<a routerLink="/home" routerLinkActive="active">Home</a>
<a routerLink="/about" routerLinkActive="active">About</a>
<a [routerLink]="['/users', userId]" routerLinkActive="active">User</a>
<a routerLink="/users/123" [queryParams]="{tab: 'posts'}"
[fragment]="'comments'">User with Query</a>
</nav>
<button (click)="navigateToUser()">Go to User</button>
<button (click)="goBack()">Go Back</button>
<!-- Router outlet -->
<router-outlet></router-outlet>
`
})
export class NavComponent {
userId = 123;
constructor(
private router: Router,
private route: ActivatedRoute
) { }
navigateToUser() {
// Programmatic navigation
this.router.navigate(['/users', this.userId], {
queryParams: { tab: 'posts' },
fragment: 'comments'
});
}
goBack() {
window.history.back();
}
}Route Parameters
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, ParamMap } from '@angular/router';
import { switchMap } from 'rxjs/operators';
@Component({
selector: 'app-user-detail',
template: `
<div *ngIf="user">
<h2>{{ user.name }}</h2>
<p>{{ user.email }}</p>
<p>Tab: {{ activeTab }}</p>
</div>
`
})
export class UserDetailComponent implements OnInit {
user: any;
activeTab: string = '';
constructor(
private route: ActivatedRoute,
private userService: UserService
) { }
ngOnInit() {
// Snapshot - one-time access
const id = this.route.snapshot.paramMap.get('id');
const tab = this.route.snapshot.queryParamMap.get('tab');
const fragment = this.route.snapshot.fragment;
// Observable - reactive to changes
this.route.paramMap.pipe(
switchMap((params: ParamMap) => {
const userId = params.get('id');
return this.userService.getUser(userId);
})
).subscribe(user => this.user = user);
// Query params
this.route.queryParams.subscribe(params => {
this.activeTab = params['tab'] || 'profile';
});
// Fragment
this.route.fragment.subscribe(fragment => {
if (fragment) {
document.getElementById(fragment)?.scrollIntoView();
}
});
}
}Route Guards
import { Injectable } from '@angular/core';
import { CanActivate, CanActivateChild, CanDeactivate,
ActivatedRouteSnapshot, RouterStateSnapshot, Router } from '@angular/router';
import { Observable } from 'rxjs';
// CanActivate - protect route access
@Injectable({ providedIn: 'root' })
export class AuthGuard implements CanActivate {
constructor(
private authService: AuthService,
private router: Router
) { }
canActivate(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot
): boolean | Observable<boolean> {
if (this.authService.isLoggedIn()) {
return true;
}
// Store intended URL
this.router.navigate(['/login'], {
queryParams: { returnUrl: state.url }
});
return false;
}
}
// CanActivateChild - protect child routes
@Injectable({ providedIn: 'root' })
export class AdminGuard implements CanActivateChild {
constructor(private authService: AuthService) { }
canActivateChild(): boolean {
return this.authService.isAdmin();
}
}
// CanDeactivate - prevent leaving route
export interface CanComponentDeactivate {
canDeactivate: () => boolean | Observable<boolean>;
}
@Injectable({ providedIn: 'root' })
export class UnsavedChangesGuard implements CanDeactivate<CanComponentDeactivate> {
canDeactivate(
component: CanComponentDeactivate
): boolean | Observable<boolean> {
return component.canDeactivate ? component.canDeactivate() : true;
}
}
// Component implementing CanComponentDeactivate
@Component({
selector: 'app-edit-user'
})
export class EditUserComponent implements CanComponentDeactivate {
hasUnsavedChanges = false;
canDeactivate(): boolean {
if (this.hasUnsavedChanges) {
return confirm('You have unsaved changes. Leave anyway?');
}
return true;
}
}
// Apply guards to routes
const routes: Routes = [
{
path: 'admin',
component: AdminComponent,
canActivate: [AuthGuard],
canActivateChild: [AdminGuard],
children: [
{ path: 'users', component: UsersComponent },
{
path: 'edit/:id',
component: EditUserComponent,
canDeactivate: [UnsavedChangesGuard]
}
]
}
];Lazy Loading
const routes: Routes = [
{
path: 'users',
loadChildren: () => import('./users/users.module').then(m => m.UsersModule)
},
{
path: 'admin',
loadChildren: () => import('./admin/admin.module').then(m => m.AdminModule),
canLoad: [AuthGuard] // Prevent loading module
}
];
// users-routing.module.ts
const routes: Routes = [
{ path: '', component: UserListComponent },
{ path: ':id', component: UserDetailComponent }
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class UsersRoutingModule { }Resolver
import { Injectable } from '@angular/core';
import { Resolve, ActivatedRouteSnapshot } from '@angular/router';
import { Observable } from 'rxjs';
@Injectable({ providedIn: 'root' })
export class UserResolver implements Resolve<User> {
constructor(private userService: UserService) { }
resolve(route: ActivatedRouteSnapshot): Observable<User> {
const id = route.paramMap.get('id');
return this.userService.getUser(id);
}
}
// Use in route
const routes: Routes = [
{
path: 'users/:id',
component: UserDetailComponent,
resolve: { user: UserResolver }
}
];
// Access resolved data in component
@Component({ /* ... */ })
export class UserDetailComponent implements OnInit {
user: User;
constructor(private route: ActivatedRoute) { }
ngOnInit() {
this.user = this.route.snapshot.data['user'];
// Or with observable
this.route.data.subscribe(data => {
this.user = data['user'];
});
}
}Keep your own version of these notes — editable, searchable, and organised by your stack.
Start free