Listen to the Navigation Lifecycle
Router Events
The Router emits an event for every step of navigation — NavigationStart, NavigationEnd, NavigationError, and more.
What you'll learn
- Subscribe to router.events
- Filter for NavigationEnd
- Build a global loading indicator
Router.events is an Observable that fires for every phase of a navigation. You can use it for analytics, global loading bars, scroll restoration, or debugging “why did this navigation fail”.
The main event types
NavigationStart— navigation kicked offRoutesRecognized— the URL parsed into a route treeGuardsCheckStart/GuardsCheckEnd— guards ranResolveStart/ResolveEnd— resolvers ranNavigationEnd— succeeded, URL is now activeNavigationCancel— guard returned false or redirectedNavigationError— something threw
Track page views
import { Component, inject } from '@angular/core';
import { NavigationEnd, Router } from '@angular/router';
import { filter } from 'rxjs';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
@Component({ selector: 'app-root', standalone: true, template: `<router-outlet />` })
export class AppComponent {
private router = inject(Router);
constructor() {
this.router.events
.pipe(
filter(e => e instanceof NavigationEnd),
takeUntilDestroyed(),
)
.subscribe((e: NavigationEnd) => {
analytics.track('pageview', { url: e.urlAfterRedirects });
});
}
} Global loading indicator
Toggle a signal while navigation is in flight.
import { signal } from '@angular/core';
import { NavigationCancel, NavigationEnd, NavigationError, NavigationStart } from '@angular/router';
loading = signal(false);
this.router.events.pipe(takeUntilDestroyed()).subscribe(e => {
if (e instanceof NavigationStart) this.loading.set(true);
if (e instanceof NavigationEnd || e instanceof NavigationCancel || e instanceof NavigationError) {
this.loading.set(false);
}
}); Render a top-bar spinner whenever loading() is true. It feels far snappier than per-route skeletons for short navigations.