简体   繁体   中英

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: client@0:0.0 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?

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>

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, eg 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, eg

<button class="btn btn-primary" (click)="toast.toogle()">toogle</button>

I create another stackblitz

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

Error npm ERR. Failed at the client@0.0:0 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: client@0:0:0 dev.ssr. `ng run client:serve-ssr` npm ERR! Exit status 1 npm ERR! npm ERR! Failed at the client@0.0.0 dev:ssr script

在此处输入图像描述

在此处输入图像描述

在此处输入图像描述

在此处输入图像描述

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.

You can also try the following npm package for snackbar. This package is having default theme as bootstrap with the Angular Material Implementation.

npm install --save @tech-pro/ngx-bootstrap-snackbar

NPM Link To Package

Demo

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM