Angular Icon Get 73% off the Angular Master bundle

See the bundle then add to cart and your discount is applied.

0 days
00 hours
00 mins
00 secs

Write Angular like a pro. Angular Icon

Follow the ultimate Angular roadmap.

Detect Route Changes with the Angular Router

In this post you’re going to learn how to detect route changes with the Angular Router.

This is a common practice when dealing with routed components, where you want to get notified of what is happening with the router (in its various phases).

For instance, there are start and end events with the router, as well as many phases and checks that get processed before navigating to each route.

An example of when to detect a route change in Angular could be showing a loading spinner or to pass some data to a logging service.

💎 Looking for query params instead of listening to all router events?

For this, we’ll create a simple App component and inject the Router into the constructor:

import { Component } from '@angular/core';
import { Router, RouterOutlet } from '@angular/router';

@Component({
  selector: 'my-app',
  standalone: true,
  imports: [RouterOutlet],
  template: `
    <router-outlet></router-outlet>
  `,
})
export class App {
  constructor(private router: Router) {}
}

Now, if you’re a seasoned Angular developer you’ll have likely seen the RouterEvent before.

This RouterEvent class serves as the base class for these router-related events (in alphabetical order):

GuardsCheckEnd
GuardsCheckStart
NavigationCancel
NavigationEnd
NavigationError
NavigationSkipped
NavigationStart
ResolveEnd
ResolveStart
RoutesRecognized

The above list of classes are potential outcomes that the router may emit. For example if a user starts to navigate to a new view, events NavigationStart and NavigationEnd will be called.

The get hold of this information (and much more) we can subscribe to the router.events Observable and log out the event:

import { Component, OnInit } from '@angular/core';
import { Router, RouterOutlet } from '@angular/router';

@Component({
  selector: 'my-app',
  standalone: true,
  imports: [RouterOutlet],
  template: `
    <router-outlet></router-outlet>
  `,
})
export class App implements OnInit {
  constructor(private router: Router) {}

  ngOnInit() {
    this.router.events.subscribe((event) => console.log(event));
  }
}

If we click and transition to a new view, we’ll see something like this being logged out in the console:

NavigationStart {...}
RoutesRecognized {...}
GuardsCheckStart {...}
ChildActivationStart {...}
ActivationStart {...}
GuardsCheckEnd {...}
ResolveStart {...}
ResolveEnd {...}
ActivationEnd {...}
ChildActivationEnd {...}
NavigationEnd {...}

Lots happening! So what about listening to events that you care about, for example just NavigationStart?

Well, you could filter them out conditionally with if statements:

import { Component, OnInit } from '@angular/core';
import { Router, RouterOutlet, NavigationStart, NavigationEnd, NavigationError } from '@angular/router';

@Component({
  selector: 'my-app',
  standalone: true,
  imports: [RouterOutlet],
  template: `
    <router-outlet></router-outlet>
  `,
})
export class App implements OnInit {
  constructor(private router: Router) {}

  ngOnInit() {
    this.router.events.subscribe((event) => {
      if (event instanceof NavigationStart) {
        // Navigation is starting... show a loading spinner perhaps?
        // blog on that here: ultimatecourses.com/blog/angular-loading-spinners-with-router-events
      }
      if (event instanceof NavigationEnd) {
        // We've finished navigating
      }
      if (event instanceof NavigationError) {
        // something went wrong, log the error
          console.log(event.error);
      }
    });
  }
}

If you want just one event, for example NavigationStart we can introduce filter() from RxJS and pipe the Observable, to only emit upon the specific event:

import { Component, OnInit } from '@angular/core';
import { Router, RouterOutlet, NavigationStart, NavigationEnd, NavigationError } from '@angular/router';

@Component({
  selector: 'my-app',
  standalone: true,
  imports: [RouterOutlet],
  template: `
    <router-outlet></router-outlet>
  `,
})
export class App implements OnInit {
  constructor(private router: Router) {}

  ngOnInit() {
    this.router.events.pipe(
      filter((event) => event instanceof NavigationStart)
    ).subscribe((event) => {
      // this only fires for `NavigationStart` and no other events
    });
  }
}

And that’s it! There are many events you can hook into by subscribing to Angular’s router events to detect route changes - one thing I should also add is that this would typically done in a central place, such as a the root component.

If, of course, you need to subscribe and detect route changes elsewhere - you’re free to do so.

Here’s a live example that logs out the events from what we’ve covered so far so you can see it in action:

Angular’s router is a powerful mechanism, and detecting route changes is just one of the many features it offers.

🏆 Check out my brand new Angular v15 course where you’ll learn Angular, TypeScript, RxJS and state management principles from beginning to expert level.

Happy routing!

Learn Angular the right way.

The most complete guide to learning Angular ever built.
Trusted by 82,951 students.

Todd Motto

with Todd Motto

Google Developer Expert icon Google Developer Expert

Related blogs 🚀

Free eBooks:

Angular Directives In-Depth eBook Cover

JavaScript Array Methods eBook Cover

NestJS Build a RESTful CRUD API eBook Cover