Published: July 05 2019
Last updated: February 19 2020

Angular 8 - Alert (Toaster) Notifications

Tutorial built with Angular 8.2.14 and Bootstrap 4.4.1

Other versions available:

Alert messages (a.k.a. toaster notifications) are an extremely common requirement in web applications for displaying status messages to the user e.g. error, success, warning and info alerts.

This tutorial shows how to implement a simple reusable alert / toaster notification module in Angular 8. The example has two pages, one with a single alert and the other with multiple alerts displayed in separate sections. Styling is done with Bootstrap 4.4 CSS.

The example project code is available on GitHub at https://github.com/cornflourblue/angular-8-alert-notifications.

Here it is in action:(See on StackBlitz at https://stackblitz.com/edit/angular-8-alerts)

Update History:

  • 19 Feb 2020 - Added features: auto close after timeout, fade out, html in alerts.
  • 18 Feb 2020 - Updated to Angular 8.2.14
  • 05 Jul 2019 - Built with Angular 8.1.0


Running the Angular 8 Alert / Toaster Example Locally

  1. Install NodeJS and NPM from https://nodejs.org.
  2. Download or clone the tutorial project source code from https://github.com/cornflourblue/angular-8-alert-notifications.
  3. Install all required npm packages by running npm install from the command line in the project root folder (where the package.json is located).
  4. Start the application by running npm start from the command line in the project root folder, this will build the application and automatically launch it in the browser on the URL http://localhost:8080.


Adding Alerts / Toaster Notifications to Your Angular 8 App

To add alerts to your Angular 8 application you'll need to copy the /src/app/_alert folder and contents from the example project, the folder contains the alert module and associated files, including:

  • alert.component.html - alert component template that contains the html for displaying alerts.
  • alert.component.ts - alert component with the logic for displaying alerts.
  • alert.model.ts - alert model class that defines the properties of an alert, it also includes the AlertType enum that defines the different types of alerts.
  • alert.module.ts - alert module that encapsulates the alert component so it can be imported by the app module.
  • alert.service.ts - alert service that can be used by any angular component or service to send alerts to alert components.
  • index.ts - barrel file that re-exports the alert module, service and model so they can be imported using only the folder path instead of the full path to each file, and also enables importing from multiple files with a single import.


Import the Alert Module into your App Module

To make the alert component available to your Angular 8 application you need to add the AlertModule to the imports array of your App Module (app.module.ts). See the app module from the example app below, the alert module is imported on line 5 and added to the imports array of the app module on line 16.

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';

import { AlertModule } from './_alert';
import { appRoutingModule } from './app.routing';

import { AppComponent } from './app.component';
import { HomeComponent } from './home';
import { MultiAlertsComponent } from './multi-alerts';

@NgModule({
    imports: [
        BrowserModule,
        FormsModule,
        AlertModule,
        appRoutingModule
    ],
    declarations: [
        AppComponent,
        HomeComponent,
        MultiAlertsComponent
    ],
    bootstrap: [AppComponent]
})
export class AppModule { }


Add the <alert></alert> tag where you want alerts to be displayed

Add the alert component tag wherever you want alert messages to be displayed.

Alert Component Options

The alert component accepts optional id and fade attributes:

  • id - used if you want to display multiple alerts in different locations (see the Multiple Alerts page in the example above). An alert component with an id attribute will display any messages sent to the alert service with a matching id, e.g. alertService.error('something broke!', { id: 'alert-1' }); will send an error message to the alert component with id="alert-1". Defaults to default-alert.
  • fade - controls if alert messages are faded out when closed. Defaults to true.

The app component template in the example /src/app/app.component.html contains a global alert tag without an id above the router-outlet tag, this alert instance displays any messages sent to the alert service without an id specified, e.g. alertService.success('you won!'); will send a success message to the global alert without an id.

<!-- main app container -->
<div class="jumbotron p-4">
    <div class="container text-center">
        <alert></alert>
        <router-outlet></router-outlet>
    </div>
</div>


Displaying Alert / Toaster Notifications in Your Angular 8 App

Once you've added support for alerts / toaster notifications to your app by following the previous steps, you can trigger alert notifications from any component in your application by simply injecting the alert service and calling one of it's methods for displaying different types of alerts: success(), error(), info() and warn().

Alert Service Options

  • The first parameter to the alert methods is a string for the alert message which can be a plain text string or HTML
  • The second parameter is an optional options object that supports an autoClose boolean property and keepAfterRouteChange boolean property:
    • autoClose - if true tells the alert component to automatically close the alert after three seconds. Default is false.
    • keepAfterRouteChange - if true prevents the alert from being closed after one route change, this is handy for displaying messages after a redirect such as a successful registration message. Default is false.

Here is the home component from the example app that injects the alertService into the constructor() so it can be called from the home component template when each of the buttons is clicked. In a real world application alert notifications can be triggered by any type of event, for example an error from an http request or a success message after a user profile is saved.

import { Component } from '@angular/core';

import { AlertService } from '../_alert';

@Component({ templateUrl: 'home.component.html' })
export class HomeComponent {
    options = {
        autoClose: false,
        keepAfterRouteChange: false
    };

    constructor(protected alertService: AlertService) { }
}


And here is the home component template containing the buttons that are bound to the methods of the alert service. It also contains a couple of checkboxes for toggling alert options.

<h1>Angular 8 Alerts</h1>
<button class="btn btn-success m-1" (click)="alertService.success('Success!!', options)">Success</button>
<button class="btn btn-danger m-1" (click)="alertService.error('Error :(', options)">Error</button>
<button class="btn btn-info m-1" (click)="alertService.info('Some info....', options)">Info</button>
<button class="btn btn-warning m-1" (click)="alertService.warn('Warning: ...', options)">Warn</button>
<button class="btn btn-outline-dark m-1" (click)="alertService.clear()">Clear</button>
<div class="form-group mt-2">
    <div class="form-check">
        <input type="checkbox" name="autoClose" id="autoClose" class="form-check-input" [(ngModel)]="options.autoClose">
        <label for="autoClose">Auto close alert after three seconds</label>
    </div>
    <div class="form-check">
        <input type="checkbox" name="keepAfterRouteChange" id="keepAfterRouteChange" class="form-check-input" [(ngModel)]="options.keepAfterRouteChange">
        <label for="keepAfterRouteChange">Keep displaying after one route change</label>
    </div>
</div>

 


 

Breakdown of the Angular 8 Alert / Toaster Notification Code

Below is a breakdown of the pieces of code used to implement the alert / toaster notification example in Angular 8, you don't need to know the details of how it all works to use the alerts in your project, it's only if you're interested in the nuts and bolts or if you want to modify the code or behaviour.


Angular 8 Alert Service

The alert service (/src/app/_alert/alert.service.ts) acts as the bridge between any component in an Angular application and the alert component that actually displays the alert / toaster messages. It contains methods for sending, clearing and subscribing to alert messages.

The service uses the RxJS Observable and Subject classes to enable communication with other components, for more information on how this works see Angular 8 - Communicating Between Components with Observable & Subject.

import { Injectable } from '@angular/core';
import { Observable, Subject } from 'rxjs';
import { filter } from 'rxjs/operators';

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

@Injectable({ providedIn: 'root' })
export class AlertService {
    private subject = new Subject<Alert>();
    private defaultId = 'default-alert';

    // enable subscribing to alerts observable
    onAlert(id = this.defaultId): Observable<Alert> {
        return this.subject.asObservable().pipe(filter(x => x && x.id === id));
    }

    // convenience methods
    success(message: string, options?: any) {
        this.alert(new Alert({ ...options, type: AlertType.Success, message }));
    }

    error(message: string, options?: any) {
        this.alert(new Alert({ ...options, type: AlertType.Error, message }));
    }

    info(message: string, options?: any) {
        this.alert(new Alert({ ...options, type: AlertType.Info, message }));
    }

    warn(message: string, options?: any) {
        this.alert(new Alert({ ...options, type: AlertType.Warning, message }));
    }

    // main alert method    
    alert(alert: Alert) {
        alert.id = alert.id || this.defaultId;
        this.subject.next(alert);
    }

    // clear alerts
    clear(id = this.defaultId) {
        this.subject.next(new Alert({ id }));
    }
}


Angular 8 Alert Component

The alert component (/src/app/_alert/alert.component.ts) controls the adding & removing of alerts in the UI, it maintains an array of alerts that are rendered by the component template.

The ngOnInit method subscribes to the observable returned from the alertService.onAlert() method, this enables the alert component to be notified whenever an alert message is sent to the alert service and add it to the alerts array for display. Sending an alert with an empty message to the alert service tells the alert component to clear the alerts array. This method also calls router.events.subscribe() to subscribe to route change events so it can automatically clear alerts on route changes.

The ngOnDestroy() method unsubscribes from the alert service and router when the component is destroyed to prevent memory leaks from orphaned subscriptions.

The removeAlert() method removes the specified alert object from the array, it allows individual alerts to be closed in the UI.

The cssClass() method returns a corresponding bootstrap alert class for each of the alert types, if you're using something other than bootstrap you can change the CSS classes returned to suit your application.

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;

        if (this.fade) {
            // fade out alert
            this.alerts.find(x => x === alert).fade = true;

            // remove alert after faded out
            setTimeout(() => {
                this.alerts = this.alerts.filter(x => x !== alert);
            }, 250);
        } else {
            // remove alert
            this.alerts = this.alerts.filter(x => x !== alert);
        }
    }

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

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

        classes.push(alertTypeClass[alert.type]);

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

        return classes.join(' ');
    }
}


Angular 8 Alert Component Template

The alert component template (/src/app/_alert/alert.component.html) renders an alert message for each alert in the alerts array using the Angular *ngFor directive.

Bootstrap 4 is used for styling the alerts / toaster notifications in the example, you can change the HTML and CSS classes in this template to suit your application if you're not using Bootstrap.

<div *ngFor="let alert of alerts" class="{{cssClass(alert)}}">
    <a class="close" (click)="removeAlert(alert)">&times;</a>
    <span [innerHTML]="alert.message"></span>
</div>


Angular 8 Alert Model and Alert Type Enum

The Alert model (/src/app/_alert/alert.model.ts) defines the properties of each alert object, and the AlertType enum defines the types of alerts allowed in the application.

export class Alert {
    id: string;
    type: AlertType;
    message: string;
    autoClose: boolean;
    keepAfterRouteChange: boolean;
    fade: boolean;

    constructor(init?:Partial<Alert>) {
        Object.assign(this, init);
    }
}

export enum AlertType {
    Success,
    Error,
    Info,
    Warning
}


Angular 8 Alert Module

The AlertModule (/src/app/_alert/alert.module.ts) encapsulates the alert component so it can be imported and used by other Angular modules.

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';

import { AlertComponent } from './alert.component';

@NgModule({
    imports: [CommonModule],
    declarations: [AlertComponent],
    exports: [AlertComponent]
})
export class AlertModule { }

 


Need Some Angular 8 Help?

Search fiverr for freelance Angular 8 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