Skip to main content

NgBootstrap: Toasts

Toasts implementation using Bootstrap and NgBootstrap

app.component.html

  • Add the app-toasts element to the DOM
<app-toasts aria-live="polite" aria-atomic="true"></app-toasts>

app-theme.scss

In the main application SCSS file, add this styling for the ngb-alert

ngb-alert {
overflow: auto;
max-height: 7rem;
white-space: pre-line;
}

toasts.component.ts

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


import { ToastService } from '../../shared/services/toast.service';


/**
* Container to display toast notifications
*/
@Component({
selector: 'app-toasts',
templateUrl: './toasts.component.html',
styleUrls: ['./toasts.component.scss']
})
export class ToastsComponent {


/**
* @ignore
*/
constructor(public toastService: ToastService) { }


/**
* Close a toast notification
*/
closeToast(toast) {
this.toastService.remove(toast);
}

}

toasts.component.html

<!--Not available until we move to NgBootstrap 5
<ngb-toast
*ngFor="let toast of toastService.toasts"
[header]="toast.title" [autohide]="true" [delay]="toast.delay || 5000"
(hide)="toastService.remove(toast)"
>{{toast.message}}</ngb-toast>-->


<ngb-alert *ngFor="let toast of toastService.toasts"
[type]="toast.type"
[dismissible]="true"
(click)="closeToast(toast)">{{toast.message}}</ngb-alert>

toasts.component.scss

:host {
position: fixed;
top: 0;
right: 0;
margin: 0.5rem;
z-index: 1200;
}

toasts.component.spec.ts

import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { NO_ERRORS_SCHEMA } from '@angular/core';


import { ToastsComponent } from './toasts.component';


describe('ToastsComponent', () => {
let component: ToastsComponent;
let fixture: ComponentFixture<ToastsComponent>;


beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ ToastsComponent ],
schemas: [ NO_ERRORS_SCHEMA ]// Ignore child components so we don't have to provide dependencies.
})
.compileComponents();
}));


beforeEach(() => {
fixture = TestBed.createComponent(ToastsComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});


it('should create', () => {
expect(component).toBeTruthy();
});
});

toast.service.ts

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


/**
* A service that manages toast notifications
*/
@Injectable({
providedIn: 'root'
})
export class ToastService {


/**
* The list of active toasts.
*/
toasts: any[];


/**
* @ignore
*/
constructor() {
this.toasts = [];
}


/**
* Show a global toast notification. The value of type follows the bootstrap theme type (e.g. 'success', 'warning', 'danger', etc),
*/
show (message: string, sendToConsole: boolean = false, title: string = null, type: string = 'success', delay: number = 3000) {
let self = this;
let toast = { title, message, type, delay };
this.toasts.push(toast);


if (sendToConsole && type === 'warning') {
console.warn(title && title.length > 0 ? title + ' - ' + message : message);
} else if(sendToConsole && type === 'danger') {
console.error(title && title.length > 0 ? title + ' - ' + message : message);
} else if(sendToConsole) {
console.log(title && title.length > 0 ? title + ' - ' + message : message);
}


// Remove toast after a short delay
setTimeout(function() {
self.remove(toast);
}, toast.delay);
}


/**
* Modified version of the show method that shows a red toast.
*/
alert(message: string, sendToConsole: boolean = false, title: string = null, delay: number = 3000) {
this.show(message, sendToConsole, title, 'danger', delay);
}


/**
* Modified version of the show method that shows a yellow toast.
*/
warn(message: string, sendToConsole: boolean = false, title: string = null, delay: number = 3000) {
this.show(message, sendToConsole, title, 'warning', delay);
}


/**
* Remove a global toast notification
*/
remove(toast) {
this.toasts = this.toasts.filter(t => t != toast);
}
}