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

Angular子组件Bootstrap 5模态框仅显示*ngFor首个对象值问题

Angular子组件模态框始终显示首个对象值的解决方案

问题描述

父组件通过*ngFor循环渲染多个app-card-component子组件,卡片区域能正常展示对应的数据,但点击任意卡片的「Inspect」按钮打开模态框时,始终显示数组中第一个对象的值——尽管getTemplateData方法里的console.log能输出当前点击对象的正确数据。

原因分析

所有子组件的模态框使用了相同的id="modal",而Bootstrap模态框是通过DOM元素的id来定位触发的。当页面存在多个相同id的元素时,浏览器只会匹配第一个符合条件的元素,因此无论点击哪个卡片的按钮,打开的都是第一个子组件的模态框,自然显示第一个对象的数据。

解决方案

方案1:为每个模态框生成唯一ID

利用子组件输入的templateObject.TemplateId(唯一标识),为模态框和触发按钮的目标ID添加唯一后缀,确保每个模态框对应唯一的触发按钮。

修改子组件child.html:

<!--CARD-->
<div class="w-100 card-wrapper-scroll">
    <div class="card h-100">
        <div class="card-body">
            <h5 class="card-title">{{templateObject.Title}}</h5>            
            <p class="card-text">{{templateObject.Description}}</p>
            <a (click)="showOrder()" class="btn btn-secondary">Alege modelul</a>
            <!-- 动态生成唯一的data-bs-target -->
            <button type="button" class="btn btn-primary" data-bs-toggle="modal" [attr.data-bs-target]="'#modal-' + templateObject.TemplateId">
                <i>Inspect</i>
            </button>
        </div>
    </div>
</div>
<--END CARD-->
<!--MODAL-->
<!-- 动态生成唯一的模态框ID -->
<div class="modal fade" [id]="'modal-' + templateObject.TemplateId" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1"
    aria-labelledby="staticBackdropLabel" aria-hidden="true">
    <div class="modal-dialog modal-fullscreen">
        <div class="modal-content">
            <div class="modal-header">
                <h5 class="modal-title" id="staticBackdropLabel">{{templateObject.Title}}</h5>
                <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
            </div>
            <div class="modal-body">
                Description - {{templateObject.Description}}
                Id - {{templateObject.TemplateId}}
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-success">Choose</button>
                <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
            </div>
        </div>
    </div>
</div>
<--END MODAL-->

方案2:用Angular控制模态框显示(更推荐)

摆脱对Bootstrap原生data-*属性的依赖,改用Angular的ViewChild获取模态框元素,手动实例化并控制模态框的显示,更符合Angular组件化思想,彻底避免ID冲突。

修改子组件child.ts:

import { Component, Input, OnInit, ViewChild, ElementRef } from '@angular/core';
import { ITemplate } from '../../models/ITemplate.interface';
import { ComponentCommunicationService } from '../services/component-communication.service'; // 替换为实际路径
import { Router } from '@angular/router';
import { Modal } from 'bootstrap'; // 确保已安装bootstrap依赖

export class CardComponent implements OnInit {

  @Input() templateObject: ITemplate = {};
  @ViewChild('modalElement') modalElement!: ElementRef;
  private modalInstance?: Modal;

  constructor(
    private componentCommunicationService: ComponentCommunicationService,
    private router: Router
  ) { }

  ngOnInit(): void {
    // 初始化Bootstrap模态框实例
    this.modalInstance = new Modal(this.modalElement.nativeElement);
  }

  openModal() {
    // 手动打开当前组件的模态框
    this.modalInstance?.show();
  }

  showOrder() {
    this.componentCommunicationService.sendFlag(false);
    this.router.navigate(
      ['/orders'],
      {
        queryParams: { order: this.templateObject.Title, Id: this.templateObject.TemplateId }
      }
    );
  }
}

修改子组件child.html:

<!--CARD-->
<div class="w-100 card-wrapper-scroll">
    <div class="card h-100">
        <div class="card-body">
            <h5 class="card-title">{{templateObject.Title}}</h5>            
            <p class="card-text">{{templateObject.Description}}</p>
            <a (click)="showOrder()" class="btn btn-secondary">Alege modelul</a>
            <!-- 调用Angular方法打开模态框 -->
            <button type="button" class="btn btn-primary" (click)="openModal()">
                <i>Inspect</i>
            </button>
        </div>
    </div>
</div>
<--END CARD-->
<!--MODAL-->
<!-- 添加模板引用变量供ViewChild获取 -->
<div #modalElement class="modal fade" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1"
    aria-labelledby="staticBackdropLabel" aria-hidden="true">
    <div class="modal-dialog modal-fullscreen">
        <div class="modal-content">
            <div class="modal-header">
                <h5 class="modal-title" id="staticBackdropLabel">{{templateObject.Title}}</h5>
                <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
            </div>
            <div class="modal-body">
                Description - {{templateObject.Description}}
                Id - {{templateObject.TemplateId}}
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-success">Choose</button>
                <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
            </div>
        </div>
    </div>
</div>
<--END MODAL-->

注意事项

  • 方案1需确保templateObject.TemplateId是全局唯一值,否则仍可能出现ID冲突;
  • 方案2需确保项目已正确安装并引入Bootstrap依赖,若使用ng-bootstrap等Angular专用Bootstrap库,可直接使用其提供的模态框组件,实现更简洁。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 05:32:02