You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular 4中Bootstrap模态框首次点击需双击问题解决方案

解决Bootstrap模态框首次双击才能打开的问题

我完全懂你这个困扰——首次点购物车图标得双击才弹出模态框,后面又正常,这其实是异步数据加载和Bootstrap模态框初始化时机不匹配搞出来的问题,咱们一步步捋清楚解决它:

问题根源

第一次点击图标时,get_My_Cart会发起异步请求拉购物车数据,但此时mycart还是空的,*ngIf="mycart && mycart.length"直接把整个模态框的DOM元素从页面里移除了。而Bootstrap的data-toggle="modal"和data-target="#exampleModal"是必须依赖DOM元素存在才能生效的,所以第一次点击只是触发了数据请求,根本没触发到模态框。等第二次点击时,数据已经加载完成,模态框DOM渲染出来了,Bootstrap能找到目标元素,自然就正常打开了。

解决方案

这里给你几个可行的方案,按需选就行:

方案1:手动控制模态框显示(最推荐)

去掉图标上的data-toggle和data-target属性,改成在数据加载完成后手动调用Bootstrap模态框的show()方法,精准把控显示时机:

修改图标代码:

<i class="fas fa-cart-plus fa-flip-horizontal text-primary" (click)="get_My_Cart($event)" style="font-size:25px;cursor: pointer;"></i>

修改组件代码:

先通过ViewChild获取模态框元素,再在数据返回后手动触发打开:

import { ViewChild, ElementRef } from '@angular/core';

// 组件类内添加
@ViewChild('exampleModal') exampleModal!: ElementRef;

get_My_Cart($event) { 
  this.publicIp.v4().then(ip => { 
    this.CartdataService.get_My_Cart_Products(ip).subscribe( 
      data => { 
        this.mycart = data['Table'] 
        this.my_Cart_Total_Amount = data['Table1'][0]['TOTAL_AMOUNT'];
        // 数据加载完成后判断是否打开模态框
        if(this.mycart && this.mycart.length > 0){
          const modalElement = this.exampleModal.nativeElement;
          const modal = new (window as any).bootstrap.Modal(modalElement);
          modal.show();
        } else {
          // 购物车为空时的提示,比如弹个toast或者alert
          alert('您的购物车是空的哦~');
        }
      }
    ); 
  }); 
}

修改模态框代码:

给模态框加模板引用变量#exampleModal,把*ngIf移到模态框内部的内容区域,让模态框根元素始终存在:

<div class="modal fade modalstyle" #exampleModal id="exampleModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true"> 
  <div class="modal-dialog" role="document"> 
    <div class="modal-content"> 
      <div class="modal-header headerHeight text-white " style="background:rgb(0, 0, 0);font-weight:bold"> 
        <h6 class="modal-title" id="exampleModalLabel">My Cart Items</h6> 
        <button #closeModalBtn type="button" class="close" data-dismiss="modal" aria-label="Close"> 
          <span aria-hidden="true">&times;</span> 
        </button> 
      </div> 
      <!-- 只控制内容显示,模态框根元素保留 -->
      <div *ngIf="mycart && mycart.length" class="modal-body"> 
        <!-- 原有的商品列表、总计等内容 -->
        <div *ngFor="let products of mycart;let i =index;"> 
          <div class="container col-sm-12"> 
            <div class="row"> 
              <div class="col-sm-4 paddingforimage"> 
                <img [src]="products['ITEM_IMAGE_PATH']"> 
              </div> 
              <div class="text-info col-sm-6"> 
                <span> 
                  <h6>{{products?.TOTAL_QTY}} &times; {{products?.ITEM_PRICE}} &#8377;</h6> 
                </span> 
                <span> 
                  <h6>{{products?.ITEM_DESC}}</h6> 
                </span> 
                <span> 
                  <h6>{{products?.TOTAL_AMT}} &#8377;</h6> 
                </span> 
              </div> 
              <div class="col-sm-1 text-right"> 
                <button type="button" class="close closebtn" aria-label="Close" (click)="detele_My_Cart(products?.ITEM_CODE)"> 
                  <span aria-hidden="true" (click)="detele_My_Cart(products?.ITEM_CODE)">&times;</span> 
                </button> 
              </div> 
            </div> 
          </div> 
          <hr> 
        </div> 
        <div class=" container row col-sm-12"> 
          <div class="col-sm-6"> 
            <strong>SHIPPING</strong> 
          </div> 
          <div class="col-sm-6 text-right">0 &#8377;</div> 
          <hr> 
          <div class="col-sm-6"> 
            <strong>TOTAL</strong> 
          </div> 
          <div class="col-sm-6 text-right">{{my_Cart_Total_Amount}} &#8377;</div> 
        </div> 
        <br> 
        <div class="container row col-sm-12" id="wrapper"> 
          <button type="button" class="btn btn-success buttonSize" data-dismiss="modal" routerLink="/cartsummary"> 
            <strong>CHECK OUT</strong> 
          </button> 
        </div> 
      </div>
      <!-- 购物车为空时的提示内容 -->
      <div *ngIf="!mycart || mycart.length === 0" class="modal-body text-center py-4">
        <p>您的购物车还没有商品~</p>
        <button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
      </div>
    </div> 
  </div> 
</div>

方案2:提前加载购物车数据

在组件初始化时(比如ngOnInit)就调用get_My_Cart方法预加载数据,这样页面加载完mycart已经有值了,首次点击时模态框DOM已经存在,Bootstrap的data属性就能正常触发:

ngOnInit(): void {
  this.get_My_Cart(null); // 根据方法参数调整,比如允许传入null
}

不过这个方法的缺点是,如果用户长时间不点购物车,数据可能过期,需要加刷新逻辑;而且一开始购物车为空的话,模态框会被渲染但内容空,得处理空状态显示。

方案3:改用Angular Bootstrap组件(如果项目允许)

如果你的项目能引入ng-bootstrap(Angular官方适配的Bootstrap组件库),它能完美配合Angular的数据绑定,避免原生Bootstrap的DOM依赖问题,模态框显示可以直接通过[(ngbModalOpen)]或者服务控制,从根源上解决首次点击无效的问题。

总结

方案1是最灵活的,既能精准控制模态框显示时机,又能优雅处理购物车为空的情况,推荐优先尝试。核心思路就是别依赖Bootstrap的自动触发,而是等数据准备好后手动打开模态框,同时保持模态框根元素始终存在,只控制内部内容的显示与否。

内容的提问来源于stack exchange,提问作者Nikson

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:52:06