Published: November 24 2022

Angular - Detect Route Change (Location Change) Event in Angular

Tutorial built with Angular 14.2.11

This is a super quick post to show how to detect and execute code on route change (location change) in Angular.

The example code is from a Angular alerts tutorial I posted recently which automatically clears alerts on location change. For the full alerts tutorial see Angular 14 - Alert (Toaster) Notifications Tutorial & Example.


Subscribe to the NavigationStart Router Event

Cutting to the chase, this is the snippet used to subscribe to router events and then execute code on NavigationStart:

ngOnInit() {
    // clear alerts on location change
    this.routeSubscription = this.router.events.subscribe(event => {
        if (event instanceof NavigationStart) {
            this.alertService.clear(this.id);
        }
    });
}


The router.events property is an RxJS Observable that emits router lifecycle events to subscribers each time the route is changed in Angular. NavigationStart is the first of a sequence of events that are emitted, there are many others including NavigationEnd, NavigationCancel, NavigationError and more. For a full list and the order they are executed see https://angular.io/api/router/Event.


Don't Forget to Unscubscribe on Destroy

This snippet unsubscribes from the route change subscription when the component is destroyed to dispose the resources held by the subscription and avoid memory leaks in the Angular app.

ngOnDestroy() {
    // unsubscribe to avoid memory leaks
    this.routeSubscription.unsubscribe();
}


Complete Angular Alert Component

Below is the complete alert component that subcribes to route changes in the ngOnInit method and unsubscribes in the ngOnDestroy() method.

The rest of the code controls the display of alerts in the UI, for more info and a live demo see Angular 14 - Alert (Toaster) Notifications Tutorial & Example.

import { Component, OnInit, OnDestroy, Input } from '@angular/core';
import { Router, NavigationStart } from '@angular/router';
import { Subscription } from 'rxjs';

import { Alert, AlertType } from './alert.model';
import { AlertService } from './alert.service';

@Component({ selector: 'alert', templateUrl: 'alert.component.html' })
export class AlertComponent implements OnInit, OnDestroy {
    @Input() id = 'default-alert';
    @Input() fade = true;

    alerts: Alert[] = [];
    alertSubscription!: Subscription;
    routeSubscription!: Subscription;

    constructor(private router: Router, private alertService: AlertService) { }

    ngOnInit() {
        // subscribe to new alert notifications
        this.alertSubscription = this.alertService.onAlert(this.id)
            .subscribe(alert => {
                // clear alerts when an empty alert is received
                if (!alert.message) {
                    // filter out alerts without 'keepAfterRouteChange' flag
                    this.alerts = this.alerts.filter(x => x.keepAfterRouteChange);

                    // remove 'keepAfterRouteChange' flag on the rest
                    this.alerts.forEach(x => delete x.keepAfterRouteChange);
                    return;
                }

                // add alert to array
                this.alerts.push(alert);

                // auto close alert if required
                if (alert.autoClose) {
                    setTimeout(() => this.removeAlert(alert), 3000);
                }
           });

        // clear alerts on location change
        this.routeSubscription = this.router.events.subscribe(event => {
            if (event instanceof NavigationStart) {
                this.alertService.clear(this.id);
            }
        });
    }

    ngOnDestroy() {
        // unsubscribe to avoid memory leaks
        this.alertSubscription.unsubscribe();
        this.routeSubscription.unsubscribe();
    }

    removeAlert(alert: Alert) {
        // check if already removed to prevent error on auto close
        if (!this.alerts.includes(alert)) return;

        // fade out alert if this.fade === true
        const timeout = this.fade ? 250 : 0;
        alert.fade = this.fade;

        setTimeout(() => {
            // filter alert out of array
            this.alerts = this.alerts.filter(x => x !== alert);
        }, timeout);
    }

    cssClass(alert: Alert) {
        if (!alert) return;

        const classes = ['alert', 'alert-dismissible'];
                
        const alertTypeClass = {
            [AlertType.Success]: 'alert-success',
            [AlertType.Error]: 'alert-danger',
            [AlertType.Info]: 'alert-info',
            [AlertType.Warning]: 'alert-warning'
        }

        if (alert.type !== undefined) {
            classes.push(alertTypeClass[alert.type]);
        }

        if (alert.fade) {
            classes.push('fade');
        }

        return classes.join(' ');
    }
}

 


Need Some Angular Help?

Search fiverr for freelance Angular developers.


Follow me for updates

On Twitter or RSS.


When I'm not coding...

Me and Tina are on a motorcycle adventure around Australia.
Come along for the ride!


Comments


Supported by