You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在ag-grid的cellRenderer中调用ng-bootstrap模态框?

嘿,我来帮你搞定这个问题!你现在的困境核心是:Ag-Grid的cellRenderer函数里没办法访问到组件的modalServiceopen方法,这是因为函数的上下文(this指向)不对,而且点击事件的回调也拿不到组件实例。下面给你几个可行的解决办法,从快速修复到符合Angular最佳实践的方案都有:


方案1:用箭头函数绑定组件上下文(快速搞定)

这个方法最简单,直接修改columnDefs里的cellRenderer赋值方式,用箭头函数包裹,这样editCellRenderer里的this就会指向你的组件实例了。另外还要把模板里的#content引用拿到组件类里:

首先在你的MyAppComponent里添加一行,获取模态框的模板引用:

import { ViewChild, TemplateRef } from '@angular/core';
// ...其他import

export class MyAppComponent implements OnInit{
  @ViewChild('content') content!: TemplateRef<any>; // 添加这行
  constructor(private modalService: NgbModal){}
  // ...其他代码
}

然后修改columnDefseditCellRenderer

columnDefs = [
  {headerName: 'name', field:'name'},
  // 用箭头函数绑定this,确保cellRenderer里的this是组件实例
  {headerName: 'edit', cellRenderer: (params) => this.editCellRenderer(params)} 
];

editCellRenderer(params){
  const div = document.createElement('div');
  div.innerHTML = '<button class="btnEdit">edit</button>'; // 这里不用转义,直接写<button>就行
  const btnEdit = div.querySelector('.btnEdit')!;
  // 这里的this已经是组件实例了,直接调用open方法
  btnEdit.addEventListener('click', () => {
    this.open(this.content);
  });
  return div;
}

这样点击按钮的时候,就能正确触发模态框了。


方案2:用Ag-Grid的Context传递组件实例(更规范)

Ag-Grid本身提供了context属性,可以用来传递上下文对象,这样在cellRenderer里就能通过params.context拿到你的组件实例:

第一步,在模板的Ag-Grid标签里添加[context]="{componentParent: this}"

<ag-grid-angular 
  style="width: 100%; height: 500px;" 
  class="ag-theme-balham" 
  [rowData]="rowData" 
  [columnDefs]="columnDefs"
  [context]="{componentParent: this}"  <!-- 新增这一行 -->
>
</ag-grid-angular>

第二步,修改editCellRenderer函数,通过params.context.componentParent访问组件的方法:

editCellRenderer(params){
  const div = document.createElement('div');
  div.innerHTML = '<button class="btnEdit">edit</button>';
  const btnEdit = div.querySelector('.btnEdit')!;
  btnEdit.addEventListener('click', () => {
    // 通过context拿到组件实例,调用open方法
    params.context.componentParent.open(params.context.componentParent.content);
  });
  return div;
}

同样别忘了在组件类里添加@ViewChild('content') content!: TemplateRef<any>;来获取模板引用哦。


方案3:用Angular组件做CellRenderer(最符合Angular最佳实践)

上面两种方法都用到了原生DOM操作,在Angular里其实更推荐用组件化的方式来做cellRenderer,这样更符合框架的设计思想,也更容易维护:

第一步:创建一个专门的编辑按钮组件

import { Component } from '@angular/core';
import { ICellRendererAngularComp } from 'ag-grid-angular';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';

@Component({
  template: `<button class="btnEdit" (click)="openModal()">edit</button>`
})
export class EditButtonComponent implements ICellRendererAngularComp {
  private params: any;

  constructor(private modalService: NgbModal) {}

  // Ag-Grid会调用这个方法传递参数
  agInit(params: any): void {
    this.params = params;
  }

  refresh(params: any): boolean {
    return false;
  }

  openModal(){
    // 通过context拿到父组件的模板引用,打开模态框
    this.params.context.componentParent.open(this.params.context.componentParent.content);
  }
}

第二步:在你的模块里配置这个组件

要确保这个组件在模块里被声明,并且AgGridModule要注册这个组件:

import { AgGridModule } from 'ag-grid-angular';
import { EditButtonComponent } from './edit-button.component';

@NgModule({
  declarations: [
    MyAppComponent,
    EditButtonComponent // 声明组件
  ],
  imports: [
    // 其他模块...
    AgGridModule.withComponents([EditButtonComponent]) // 注册给Ag-Grid
  ]
})
export class AppModule {}

第三步:修改父组件的columnDefs

把原来的cellRenderer换成cellRendererFramework,指定我们的组件:

columnDefs = [
  {headerName: 'name', field:'name'},
  {
    headerName: 'edit',
    cellRendererFramework: EditButtonComponent // 使用我们的Angular组件
  }
];

第四步:父组件的Ag-Grid标签还是要加[context]="{componentParent: this}",并且组件类里要有@ViewChild('content') content!: TemplateRef<any>;

这种方法完全摆脱了原生DOM操作,用Angular的组件方式来实现,后续要修改按钮样式或者逻辑都非常方便。


最后提个小细节:你原来代码里的innerHTML写了&lt;button&gt;,其实直接写<button>就可以了,不用转义;另外在TypeScript里尽量用const/let代替var,代码会更规范。

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

火山引擎 最新活动