Router Event Lifecycle
The Router emits events during each navigation lifecycle. You can subscribe to these events to react to navigation changes.
Router Event Types
import { Router, NavigationStart, NavigationEnd, NavigationCancel, NavigationError } from '@angular/router';
@Component({
selector: 'app-root',
template: `...`,
})
export class AppComponent implements OnInit, OnDestroy {
private router = inject(Router);
private destroy$ = new Subject<void>();
ngOnInit(): void {
this.router.events.pipe(
filter((event): event is NavigationEnd => event instanceof NavigationEnd),
takeUntil(this.destroy$)
).subscribe(event => {
console.log('Navigation ended:', event.url);
});
}
ngOnDestroy(): void {
this.destroy$.next();
this.destroy$.complete();
}
}
Event Sequence
NavigationStart
→ RoutesRecognized
→ GuardsCheckStart
→ ChildActivationStart
→ ActivationStart
→ GuardsCheckEnd
→ ResolveStart
→ ResolveEnd
→ ActivationEnd
→ ChildActivationEnd
→ NavigationEnd
Or on failure:
NavigationStart → NavigationCancel
NavigationStart → NavigationError
Filtering Events
import { filter } from 'rxjs/operators';
this.router.events.pipe(
filter((event) => event instanceof NavigationStart)
).subscribe(event => {
console.log('Navigation started:', event.url);
});
Practical Router Event Patterns
Router events enable common UX patterns like progress bars and analytics tracking.
Progress Bar
@Component({
selector: 'app-progress-bar',
template: `
<div class="progress-bar" [style.width.%]="progress" *ngIf="isNavigating">
`,
})
export class ProgressBarComponent implements OnInit, OnDestroy {
private router = inject(Router);
private destroy$ = new Subject<void>();
isNavigating = false;
progress = 0;
ngOnInit(): void {
this.router.events.pipe(
takeUntil(this.destroy$)
).subscribe(event => {
if (event instanceof NavigationStart) {
this.isNavigating = true;
this.progress = 0;
this.animateProgress();
}
if (event instanceof NavigationEnd || event instanceof NavigationCancel) {
this.progress = 100;
setTimeout(() => this.isNavigating = false, 200);
}
});
}
private animateProgress(): void {
const interval = setInterval(() => {
if (this.progress < 90) {
this.progress += 10;
} else {
clearInterval(interval);
}
}, 100);
}
ngOnDestroy(): void {
this.destroy$.next();
this.destroy$.complete();
}
}
Analytics Tracking
@Injectable({ providedIn: 'root' })
export class AnalyticsService {
private router = inject(Router);
trackPageViews(): void {
this.router.events.pipe(
filter((event): event is NavigationEnd => event instanceof NavigationEnd)
).subscribe(event => {
gtag('event', 'page_view', { page_path: event.url });
});
}
}
Scroll to Top on Navigation
this.router.events.pipe(
filter((event): event is NavigationEnd => event instanceof NavigationEnd)
).subscribe(() => {
window.scrollTo(0, 0);
});
Cancel In-Flight Navigation
this.router.events.pipe(
filter((event): event is NavigationStart => event instanceof NavigationStart),
switchMap(() => {
// Cancel previous in-flight navigation
return this.someService.cancelPending();
})
).subscribe();
Quiz
1. Which router events bookend a successful navigation?
2. How do you filter router events for a specific type?
3. What is a practical use of router events?
Flashcards
Question
Which events bookend navigation?
Click to reveal answer
Answer
NavigationStart and NavigationEnd. Also NavigationCancel and NavigationError for failures.
Question
How do you filter router events?
Click to reveal answer
Answer
filter(event => event instanceof NavigationEnd) — RxJS filter with instanceof.
Question
What are practical uses of router events?
Click to reveal answer
Answer
Progress bars, analytics tracking, scroll-to-top, canceling in-flight navigations.
Revision Notes
Key Takeaways
- 1. NavigationStart and NavigationEnd bookend transitions
- 2. Filter events with RxJS filter + instanceof
- 3. Progress bars use NavigationStart/End
- 4. Analytics tracking uses NavigationEnd
Interview Tips
- • Explain the router event lifecycle
- • Be ready to describe practical event patterns
- • Mention switchMap for canceling in-flight navigations
Cheat Sheet
Router Events Cheat Sheet
Event sequence:
NavigationStart → GuardsCheck → Resolve → NavigationEnd
Filter events:
this.router.events.pipe(
filter((event): event is NavigationEnd => event instanceof NavigationEnd)
).subscribe(event => { ... });
Progress bar:
- NavigationStart: show bar
- NavigationEnd: hide bar
Analytics:
- NavigationEnd: track page view