Angular router: routing, guards, and lazy loading
Angular Router
The Angular Router maps URL paths to components, supports navigation guards, lazy loading, and nested routes.
Basic Setup
typescript
// app.routes.ts
import { Routes } from '@angular/router';
export const routes: Routes = [
{ path: '', component: HomeComponent },
{ path: 'about', component: AboutComponent },
{ path: 'users/:id', component: UserDetailComponent },
{ path: '**', component: NotFoundComponent }, // Wildcard
];html
<!-- app.component.html -->
<nav>
<a routerLink="/" routerLinkActive="active">Home</a>
<a routerLink="/about" routerLinkActive="active">About</a>
</nav>
<router-outlet></router-outlet> <!-- Route content renders here -->Route Parameters
typescript
import { ActivatedRoute } from '@angular/router';
@Component({ /* ... */ })
export class UserDetailComponent implements OnInit {
private route = inject(ActivatedRoute);
ngOnInit() {
// Snapshot (one-time read)
const id = this.route.snapshot.paramMap.get('id');
// Observable (reacts to param changes)
this.route.paramMap.subscribe(params => {
const id = params.get('id');
this.loadUser(id!);
});
}
}Lazy Loading
Load feature modules on demand to reduce initial bundle:
typescript
export const routes: Routes = [
{
path: 'admin',
loadComponent: () => import('./admin/admin.component')
.then(m => m.AdminComponent),
},
{
path: 'dashboard',
loadChildren: () => import('./dashboard/dashboard.routes')
.then(m => m.DASHBOARD_ROUTES),
},
];Route Guards
canActivate — Protect routes
typescript
import { CanActivateFn } from '@angular/router';
export const authGuard: CanActivateFn = (route, state) => {
const authService = inject(AuthService);
const router = inject(Router);
if (authService.isLoggedIn()) {
return true;
}
return router.createUrlTree(['/login'], {
queryParams: { returnUrl: state.url }
});
};
// Usage in routes
{ path: 'dashboard', component: DashboardComponent, canActivate: [authGuard] }canDeactivate — Prevent leaving
typescript
export const unsavedChangesGuard: CanDeactivateFn<FormComponent> = (component) => {
if (component.hasUnsavedChanges()) {
return confirm('You have unsaved changes. Leave anyway?');
}
return true;
};Resolvers — Pre-fetch data
typescript
export const userResolver: ResolveFn<User> = (route) => {
const userService = inject(UserService);
const id = route.paramMap.get('id')!;
return userService.getUserById(id);
};
// Route config
{
path: 'users/:id',
component: UserDetailComponent,
resolve: { user: userResolver }
}
// In component
export class UserDetailComponent {
private route = inject(ActivatedRoute);
user = this.route.snapshot.data['user'] as User;
}Nested Routes
typescript
{
path: 'settings',
component: SettingsLayoutComponent,
children: [
{ path: '', redirectTo: 'profile', pathMatch: 'full' },
{ path: 'profile', component: ProfileSettingsComponent },
{ path: 'security', component: SecuritySettingsComponent },
{ path: 'notifications', component: NotificationSettingsComponent },
]
}Programmatic Navigation
typescript
export class AppComponent {
private router = inject(Router);
goToUser(id: string) {
this.router.navigate(['/users', id]);
}
goWithQuery() {
this.router.navigate(['/search'], {
queryParams: { q: 'angular', page: 1 }
});
}
}Important:
Angular Router provides declarative routing with guards for access control and lazy loading for performance. Use functional guards (CanActivateFn) over class-based guards. Always lazy load feature routes using loadComponent/loadChildren. Use resolvers to pre-fetch data before navigation.
Short Answer
Interview readyPremium
A concise answer to help you respond confidently on this topic during an interview.