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);
}
}