'Angular 11 Universal and Bootstrap 5 Toast not working- new bootstrap TS2304: Cannot find name 'bootstrap', crushed
I work with Angular 11 Universal - server side rendering. I'm trying to implement Bootstrap 5 toasts (css works well), but it doesn't understand class new bootstrap: 
angular.json - it's imported properly
"styles": [
"src/styles.scss",
"node_modules/bootstrap/dist/css/bootstrap.min.css"
],
"scripts": [
"node_modules/@popperjs/core/dist/umd/popper.min.js",
"node_modules/bootstrap/dist/js/bootstrap.min.js"
]
package.json
"@angular/platform-browser": "~11.2.7",
"@angular/platform-browser-dynamic": "~11.2.7",
"@angular/platform-server": "~11.2.7",
"@angular/router": "~11.2.7",
"@nguniversal/express-engine": "^11.2.1",
"@popperjs/core": "^2.9.2",
"bootstrap": "^5.0.0-beta3",
"express": "^4.15.2",
"popper.js": "^1.16.1",
I was trying to implement toasts with initial JS code:
import {
AfterViewInit,
Component,
ElementRef,
EventEmitter,
Inject,
Input,
OnInit,
Output,
PLATFORM_ID,
ViewChild
} from '@angular/core';
import { Toast } from '../../../../../node_modules/bootstrap/dist/js/bootstrap.min.js'
import {isPlatformBrowser} from "@angular/common";
@Component({
selector: 'app-toast',
templateUrl: './toast.component.html',
styleUrls: ['./toast.component.scss']
})
export class ToastComponent implements OnInit, AfterViewInit {
@Output() closeHit: EventEmitter<boolean> = new EventEmitter<boolean>();
// @Input() title: string = "Toast";
@Input() message: string = 'Enter message here';
@ViewChild('toast') toast: ElementRef<HTMLDivElement>
constructor(@Inject(PLATFORM_ID) private platformId: Object) {
if (isPlatformBrowser(this.platformId)) {
// var toastElList = [].slice.call(document.querySelectorAll('.toast'))
// var toastList = toastElList.map(function (toastEl) {
return new bootstrap.Toast(this.toast, {})
// })
new Toast(this.toast);
// Array.from(document.querySelectorAll('.toast'))
// .forEach(toastNode => new Toast(toastNode))
}
}
ngOnInit(): void {
}
ngAfterViewInit() {
}
}
But it don't understand class bootstrap - in new bootstrap TS2304: Cannot find name 'bootstrap'.
2 variant with importing toast directly from bootstrap.js is breaking the app new Toast(this.toast);
ReferenceError: document is not defined
A server error has occurred.
node exited with 1 code.
connect ECONNREFUSED 127.0.0.1:62043
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! [email protected] dev:ssr: ng run client:serve-ssr
npm ERR! Exit status 1
Please, help! Is there any way to use Bootstrap 5 functionality for toasts, modals in Angular Universal?
Solution 1:[1]
Angular 12 & Bootstrap 5 .TS
@ViewChild('myToast',{static:true}) toastEl!: ElementRef<HTMLDivElement>;
toast: Toast | null = null;
ngOnInit()
{
this.toast = new Toast(this.toastEl.nativeElement,{});
}
show(){
this.toast!.show();
}
HTML
<button type="button" class="btn btn-primary" id="liveToastBtn"
(click)="show()">Show live toast</button>
<div #myToast role="alert" aria-live="assertive" aria-atomic="true"
class="toast fade" data-bs-autohide="false">
<div class="toast-header">
<img src="..." class="rounded me-2" alt="...">
<strong class="me-auto">Bootstrap</strong>
<small>11 mins ago</small>
<button type="button" class="btn-close" data-bs-dismiss="toast" aria-
label="Close"></button>
</div>
<div class="toast-body">
Hello, world! This is a toast message.
</div>
</div>
Solution 2:[2]
Add the bootstrap/Types
npm i @types/bootstrap
Then in your component import Toast
import {Toast} from 'bootstrap'
Use a template reference for your toast
<div #myToast role="alert" aria-live="assertive" aria-atomic="true" class="toast fade" data-bs-autohide="false">
<div class="toast-header">
<img src="..." class="rounded me-2" alt="...">
<strong class="me-auto">Bootstrap</strong>
<small>11 mins ago</small>
<button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button>
</div>
<div class="toast-body">
Hello, world! This is a toast message.
</div>
</div>
And use ViewChild with static true to create the Toast element in ngOnInit
@ViewChild('myToast',{static:true}) toastEl: any
isClosed(){
return !this.toastEl.nativeElement.classList.contains('show')
}
toast:any
ngOnInit()
{
this.toast=new Toast(this.toastEl.nativeElement,{})
}
Then use toast.show() or toast.hide()
see the stackblitz
NOTE: You can also use librarys that has toast component, e.g. ng-bootstrap (I put this because is closer to bootstrap and is "pure" Angular
Update We can improve the code using a directive
If we create a directive like
import {Directive,ElementRef} from '@angular/core'
import {Toast} from 'bootstrap'
@Directive({
selector: '.toast', //<--(1)
})
export class ToastDirective {
toast:any;
isClosed(){
return !this.el.nativeElement.classList.contains('show')
}
constructor(private el:ElementRef){
this.toast=new Toast(this.el.nativeElement)
}
toogle()
{
if (this.isClosed())
this.toast.show();
else
this.toast.hide();
}
hide(){
this.toast.hide();
}
show(){
this.toast.show();
}
}
(1) make that the directive is applied to all the div with class="toast".
We has all "encapsulated", now if we has a toast
<div #myToast role="alert" aria-live="assertive" aria-atomic="true" class="toast fade" data-bs-autohide="false">
...
</div>
ViewChild is now
@ViewChild('myToast',{static:true,read:ToastDirective}) toast: ToastDirective
And we can do, e.g.
<button class="btn btn-primary" (click)="toast.toogle()">toogle</button>
I create another stackblitz
Solution 3:[3]
npm install bootstrap
npm install @types/bootstrap
code...
const Bootstrap = await import('bootstrap');
const Modal = new Bootstrap.Modal(...element..., ...options...);
angular.json
"build": {
...,
"options": {
...,
"allowedCommonJsDependencies": [
"bootstrap"
],
...
},
...
}
Toast try like this
Solution 4:[4]
Error npm ERR! Failed at the [email protected] dev:ssr script - it's not rendering on server as I understand, bootstrap needs DOM, but this is just server side.
The app is crashed:
E:\PRACTICE\MYPETPROJECTS\tanechka\client\dist\client\server\main.js:79069
EventHandler.on(document, EVENT_CLICK_DATA_API$7, SELECTOR_DISMISS, Alert.handleDismiss(new Alert()));
^
ReferenceError: document is not defined
at E:\PRACTICE\MYPETPROJECTS\tanechka\client\dist\client\server\main.js:79069:19
at E:\PRACTICE\MYPETPROJECTS\tanechka\client\dist\client\server\main.js:78335:28
at Object.SYky (E:\PRACTICE\MYPETPROJECTS\tanechka\client\dist\client\server\main.js:78337:2)
at __webpack_require__ (E:\PRACTICE\MYPETPROJECTS\tanechka\client\dist\client\server\main.js:26:30)
at Module.Mvz9 (E:\PRACTICE\MYPETPROJECTS\tanechka\client\dist\client\server\main.js:71515:67)
at __webpack_require__ (E:\PRACTICE\MYPETPROJECTS\tanechka\client\dist\client\server\main.js:26:30)
at Module.PCNd (E:\PRACTICE\MYPETPROJECTS\tanechka\client\dist\client\server\main.js:74232:91)
at __webpack_require__ (E:\PRACTICE\MYPETPROJECTS\tanechka\client\dist\client\server\main.js:26:30)
at Module.ZAI4 (E:\PRACTICE\MYPETPROJECTS\tanechka\client\dist\client\server\main.js:90421:79)
at __webpack_require__ (E:\PRACTICE\MYPETPROJECTS\tanechka\client\dist\client\server\main.js:26:30)
A server error has occurred.
node exited with 1 code.
connect ECONNREFUSED 127.0.0.1:60499
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! [email protected] dev:ssr: `ng run client:serve-ssr`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the [email protected] dev:ssr script
Solution 5:[5]
Single right decision for me was to refuse from using Bootstrap in Angular Universal and replacing it with Angular Material SnackBar and utilities.
https://material.angular.io/components/snack-bar/examples
This line of code
this.toast = new Toast(this.toastEl.nativeElement,{});
- calling new Toast - it didn't work in Universal Angular for how I was trying to implement it in any ways.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | May Alvarado |
| Solution 2 | |
| Solution 3 | |
| Solution 4 | |
| Solution 5 | Tatyana Molchanova |




