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

Ag-Grid v20加载数据异常:仅开控制台正常,报componentFromFramework空指针错误

Ag-Grid v20 结合 Observable 加载数据时的控制台依赖问题

我用 Observable 给 Ag-Grid v20 填充数据,在 ngOnInit 里订阅 API 请求,把返回数据映射适配列定义后存入变量,打算等网格就绪后在 onGridReady 里加载数据。但奇怪的是,只有打开开发者控制台时数据能正常加载,关闭控制台就会报错:

core.js:5973 ERROR TypeError: Cannot read properties of null (reading 'componentFromFramework')
    at push.lXBk.UserComponentFactory.lookupComponentClassDef (userComponentFactory.js:277:1)
    at push.xPbl.CellComp.chooseCellRenderer (cellComp.js:638:1)
    at new CellComp (cellComp.js:75:1)
    at rowComp.js:959:1
    at Array.forEach (<anonymous>)
    at push.3oHf.RowComp.createCells (rowComp.js:958:1)
    at push.3oHf.RowComp.createRowContainer (rowComp.js:182:98)
    at push.3oHf.RowComp.setupNormalRowContainers (rowComp.js:255:1)
    at push.3oHf.RowComp.setupRowContainers (rowComp.js:237:1)
    at push.3oHf.RowComp.init (rowComp.js:80:1)

TypeScript 组件代码

assets?: AssetElement[] = [];
tmpAssets?: AssetElement[] = [];
assets$?: Observable<AssetElement[]>;

gridApi?: GridApi;
private subscription?: Subscription;

constructor(private router: Router,
            private selectedRowsService: SelectedRowsService,
            private myRamService: MyRamService) {
}

ngOnInit(): void {
  const busObjArr: AssetElement[] = [];
  this.subscription = this.myRamService.getAssests().pipe(
    map(res =>
      res.reduce((acc, bo) =>
        acc.concat(buildRowDataFromCollection(bo, 'assets', 'application_')), busObjArr)
    ), tap(res => console.log('new value'))
  ).subscribe(res =>
    this.assets = res
  );
}

updateSelection() {
  const array = this.gridApi?.getSelectedRows();
  this.router.navigate(['update']);
}

onGridReady(params: GridReadyEvent) {
  this.gridApi = params.api;
  console.log('Grid is ready !!! assets : ' + this.assets?.length);
  // @ts-ignore
  if (this.assets?.length >= 0) {
    this.loadData(params.api);
  }
}

onClick() {
  this.gridApi?.updateRowData({add: this.assets});
  this.subscription?.unsubscribe();
}

ngAfterViewInit(): void {
  this.tmpAssets = this.assets;
}

onFirstDataRendered($event: any) {
  console.log('onFirstDataRendered !!! assets : ' + this.assets?.length);
}

loadData(gridApi: GridApi) {
  // @ts-ignore
  gridApi.setRowData(this.tmpAssets);
}

HTML 模板代码

<div class="card card-bordered">
  <div class="card-header">
    <button (click)="onClick()" class="btn btn-lg btn-discreet-info ">DataRefresh</button>
    <button (click)="updateSelection()" class="btn btn-lg btn-discreet-info ">Update Selection</button>
  </div>
  <div class="card-body h-100 w-100 d-flex flex-column">
    <div style="height: 50rem">
      <div class="ag-theme-sg-bootstrap ag-theme-sg-bootstrap-condensed flex-grow-1 h-100">
          <ag-grid-angular
          #agGrid
          (gridReady)="onGridReady($event)"
          [rowSelection]="'multiple'"
          [rowData]="tmpAssets"
          [columnDefs]="columnDefs"
          (firstDataRendered)="onFirstDataRendered($event)"
          [onGridReady]=""
          headerHeight="30"
          style="height: 100%">
        </ag-grid-angular>
      </div>
    </div>
  </div>
  <div class="card-footer">CARD FOOTER</div>
</div>

问题分析与修复方案

核心问题

  1. 时序不匹配:API 请求是异步的,onGridReady 可能在数据返回前就执行,此时 assets 为空,但你用 @ts-ignore 跳过类型检查,导致网格渲染空数据时出错;打开控制台时,console.log 会阻塞线程,间接让数据请求先完成,所以能正常加载。
  2. 数据同步错误:ngAfterViewInit 执行时,assets 大概率还没拿到 API 返回值,tmpAssets 被赋值为空,而模板绑定的是 tmpAssets,进一步加剧了时序问题。
  3. 冗余配置冲突:HTML 里重复写了 [onGridReady]="",会覆盖之前的 (gridReady) 绑定,导致逻辑混乱。

修复步骤

方案1:用 AsyncPipe 自动管理数据(推荐)

去掉手动订阅,让 Angular 自动处理 Observable 的订阅和数据同步,彻底解决时序问题:

// 组件代码修改
assets$!: Observable<AssetElement[]>;

ngOnInit(): void {
  const busObjArr: AssetElement[] = [];
  this.assets$ = this.myRamService.getAssests().pipe(
    map(res =>
      res.reduce((acc, bo) =>
        acc.concat(buildRowDataFromCollection(bo, 'assets', 'application_')), busObjArr)
    )
  );
}

模板中修改 rowData 绑定:

<ag-grid-angular
  #agGrid
  (gridReady)="onGridReady($event)"
  [rowSelection]="'multiple'"
  [rowData]="assets$ | async" <!-- 替换原 tmpAssets 绑定 -->
  [columnDefs]="columnDefs"
  (firstDataRendered)="onFirstDataRendered($event)"
  headerHeight="30"
  style="height: 100%">
</ag-grid-angular>

方案2:手动处理数据时序(如果坚持手动订阅)

确保数据返回后再通知网格加载,同时修复冗余配置:

// 组件代码修改
ngOnInit(): void {
  const busObjArr: AssetElement[] = [];
  this.subscription = this.myRamService.getAssests().pipe(
    map(res =>
      res.reduce((acc, bo) =>
        acc.concat(buildRowDataFromCollection(bo, 'assets', 'application_')), busObjArr)
    )
  ).subscribe(res => {
    this.assets = res;
    // 数据返回后,如果网格已就绪,直接更新数据
    this.gridApi?.setRowData(res);
  });
}

onGridReady(params: GridReadyEvent) {
  this.gridApi = params.api;
  // 如果此时已有数据,直接加载
  if (this.assets?.length) {
    params.api.setRowData(this.assets);
  }
}

同时删除 HTML 中的 [onGridReady]="" 配置,以及 ngAfterViewInit 中无效的 tmpAssets 赋值。

方案3:检查列定义的自定义组件

错误提示中的 componentFromFramework 指向单元格渲染器问题,确保所有自定义组件都已正确注册到 Ag-Grid:

// 在模块中导入并声明自定义渲染组件
import { AgGridModule } from 'ag-grid-angular';
import { YourCustomRendererComponent } from './your-renderer.component';

@NgModule({
  imports: [
    AgGridModule.withComponents([YourCustomRendererComponent])
  ]
})

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 00:55:13