Angular 11 Universal 和 Bootstrap 5 Toast 不工作 - 新的 bootstrap TS2304:找不到名称“bootstrap”,粉碎了

问题描述 投票:0回答:6

我使用 Angular 11 Universal - 服务器端渲染。我正在尝试实现 Bootstrap 5 toast(css 效果很好),但它不理解新的 bootstrap 类:

angular.json - 已正确导入

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

我试图用最初的JS代码来实现toasts:

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() {
  }

}

但它不理解类引导程序 - 在新的引导程序 TS2304 中:找不到名称“引导程序”。

2 直接从 bootstrap.js 导入 toast 的变体正在破坏应用程序 新的吐司(this.toast);

ReferenceError:文档未定义 服务器发生错误。 节点退出并带有 1 个代码。 连接 ECONNREFUSED 127.0.0.1:62043 npm 错误!代码 生命周期 npm 错误!错误号1 npm 错误! [电子邮件受保护] dev:ssr:

ng run client:serve-ssr
npm 错误!退出状态1

请帮忙!有没有办法在 Angular Universal 中使用 Bootstrap 5 的 toasts、modals 功能?

angular twitter-bootstrap rendering server-side universal
6个回答
4
投票

添加引导程序/类型

npm i @types/bootstrap

然后在你的组件中导入Toast

import {Toast} from 'bootstrap'

为您的吐司使用模板参考

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

并使用带有 static true 的 ViewChild 在 ngOnInit 中创建 Toast 元素

  @ViewChild('myToast',{static:true}) toastEl: any
  isClosed(){
    return !this.toastEl.nativeElement.classList.contains('show')
  }
  toast:any
  ngOnInit()
  {
    this.toast=new Toast(this.toastEl.nativeElement,{})
  }

然后使用 toast.show() 或 toast.hide()

参见stackblitz

注意:您还可以使用具有 toast 组件的库,例如ng-bootstrap(我这么说是因为它更接近 bootstrap 并且是“纯粹的”Angular

更新我们可以使用指令改进代码

如果我们创建一个像

这样的指令
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) 使该指令应用于所有 class="toast" 的 div。

我们已经全部“封装”了,现在我们干杯吧

<div #myToast role="alert" aria-live="assertive" aria-atomic="true" class="toast fade" data-bs-autohide="false">
...
</div>

ViewChild 现在

 @ViewChild('myToast',{static:true,read:ToastDirective}) toast: ToastDirective

我们可以做,例如

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

我创建了另一个stackblitz


2
投票

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>

2
投票
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"
        ],
        ...
    },
    ...
}

吐司 尝试这样


0
投票

对我来说唯一正确的决定是拒绝在 Angular Universal 中使用 Bootstrap,并用 Angular Material SnackBar 和实用程序替换它。

https://material.angular.io/components/snack-bar/examples

这行代码

this.toast = new Toast(this.toastEl.nativeElement,{});

  • 调用 new Toast - 它在 Universal Angular 中不起作用,因为我试图以任何方式实现它。

0
投票

找到了一种更好、更简单的方法来做到这一点。 确保 bootstrap、jquery 和 @popper.js 已安装在您的 Angular 项目中

npm i bootstrap --save

其他人也一样...

HTML

<button type="button" class="btn btn-primary" (click)="showToast()">
    Show Toast
  </button>
  <div class="toast-container position-fixed top-0 end-0 p-3">
    <div
      id="liveToast"
      class="toast"
      role="alert"
      aria-live="assertive"
      aria-atomic="true"
    >
      <div class="toast-header">
        <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>
  </div>

TS文件

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

declare var bootstrap: any; // To make sure angular recognizes the global bootstrap

@Component({
    selector: "admin-users-create-component",
    templateUrl: "admin-users-create.component.html",
    standalone: true,
    imports: []
})
export class AdminUsersCreateComponent{

    constructor(){}

    showToast(): void {
        const toastEl = document.getElementById('liveToast');
        const toast = new bootstrap.Toast(toastEl); // Initialize the toast
        toast.show(); // Show the toast
      }
}

这应该工作得很好。


-1
投票

错误 npm 错误! [email protected] dev:ssr 脚本失败 - 据我所知,它没有在服务器上渲染,引导程序需要 DOM,但这只是服务器端。

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

© www.soinside.com 2019 - 2024. All rights reserved.