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>
问题分析与修复方案
核心问题
- 时序不匹配:API 请求是异步的,
onGridReady可能在数据返回前就执行,此时assets为空,但你用@ts-ignore跳过类型检查,导致网格渲染空数据时出错;打开控制台时,console.log会阻塞线程,间接让数据请求先完成,所以能正常加载。 - 数据同步错误:
ngAfterViewInit执行时,assets大概率还没拿到 API 返回值,tmpAssets被赋值为空,而模板绑定的是tmpAssets,进一步加剧了时序问题。 - 冗余配置冲突: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
相关产品推荐
相关产品推荐

