如何访问@ng-bootstrap模态框ng-template内的模板引用变量操作DOM
问题原因
<ng-template>包裹的内容属于未实例化的模板片段,默认不会渲染到组件的DOM树中,@ViewChild/@ContentChild只能查询到当前组件已渲染完成的元素,因此初始化阶段无法获取到内部的oppGrid。- ng-bootstrap调用
modalService.open()方法时,才会异步将ng-template的内容实例化并插入到页面的模态框容器中,该过程脱离了Angular常规变更检测周期,因此即使在shown事件回调中,也需要手动触发变更检测才能让@ViewChild查询到刚渲染的元素。
解决方法
方案1:配合变更检测使用@ViewChild
修改组件ts代码如下:
import { Component,ElementRef, ViewChild, AfterViewInit, ChangeDetectorRef} from '@angular/core'; import {NgbModal, NgbModalRef} from '@ng-bootstrap/ng-bootstrap'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent implements AfterViewInit{ modalRef:NgbModalRef; @ViewChild("content") gameModal:ElementRef; // 用@ViewChild声明,static设为false(非静态查询,随渲染动态更新) @ViewChild('oppGrid', { static: false }) oppGrid!: ElementRef; constructor( private modalService: NgbModal, // 注入变更检测器 private cdr: ChangeDetectorRef ){} ngAfterViewInit(){ this.modalRef = this.modalService.open(this.gameModal,{size:"xl"}); this.modalRef.shown.subscribe(()=>{ // 手动触发变更检测,更新@ViewChild查询结果 this.cdr.detectChanges(); console.log(this.oppGrid); // 此时可以正常获取到ElementRef // 这里可以执行DOM操作 }); } }
方案2:直接从模态框实例查询DOM
如果不想依赖变更检测,也可以直接从模态框实例的DOM节点中查询目标元素,使用该方案建议先给目标元素加唯一id属性<div id="oppGrid" #oppGrid ...>,查询时更准确:
ngAfterViewInit(){ this.modalRef = this.modalService.open(this.gameModal,{size:"xl"}); this.modalRef.shown.subscribe(()=>{ // 从模态框的根DOM节点查询目标元素 const oppGrid = this.modalRef.location.nativeElement.querySelector('#oppGrid'); console.log(oppGrid); // 直接获取到原生DOM节点 }); }
注意事项
模态框关闭后,内部DOM会被销毁,oppGrid会变回undefined,避免在模态框关闭后操作该变量。
内容的提问来源于stack exchange,提问作者Rae-Win
相关产品推荐
相关产品推荐

