Angular 14中AG Grid行更新异常:文件上传后网格不自动刷新
解决Angular 14 + AG Grid文件上传后按钮不自动禁用的问题
问题描述
使用Angular 14和AG Grid,某列通过单元格渲染器实现文件上传按钮,上传成功后按钮需禁用,但网格无法自动更新状态,仅浏览器刷新后生效,尝试过Grid API的刷新单元格、重置配置等方法无效。
问题根源
- AG Grid依赖不可变数据触发更新,直接修改原数组元素不会被网格感知
- 单元格渲染器的
refresh方法返回false,导致网格不会主动更新渲染器状态 - 未正确调用AG Grid API通知数据变化
解决方案
1. 保证数据更新的不可变性
直接修改原数组无法触发AG Grid更新,需创建新数组替换:
修改单元格渲染器中的updateInvoiceResponse方法:
private async updateInvoiceResponse(invoiceId: string, invoiceResponse: Invoice[]): Promise<void> { const updatedInvoice = await this.invoiceService.SearchSingleInvoice(invoiceId); const index = invoiceResponse.findIndex(responseInvoice => responseInvoice.id === updatedInvoice.id); if (updatedInvoice && index !== -1) { // 创建新数组,保持不可变性 const newInvoiceResponse = [...invoiceResponse]; newInvoiceResponse[index] = updatedInvoice; this.invoiceService.setSearchInvoicesResponse(newInvoiceResponse); } }
同时在组件订阅中通知AG Grid更新数据:
ngOnInit(): void { this.invoiceSearchSubscription = this.invoiceService.invoiceResponse$().subscribe((invoiceResponse: Invoice[]) => { this.invoiceResponse = invoiceResponse; // 通知AG Grid更新行数据 this.gridApi?.setRowData(this.invoiceResponse); }); }
2. 修复单元格渲染器的refresh方法
将refresh方法返回true,并手动更新参数,让网格可以复用渲染器并更新状态:
refresh(params: ICellRendererParams<any>): boolean { this.params = params; // 可在此处手动更新按钮状态逻辑 return true; }
模板中绑定按钮禁用状态到行数据字段:
<button [disabled]="params.data.documentUploaded" (change)="onFileSelected($event, params.data)">上传文件</button>
3. 上传成功后直接刷新对应单元格
文件上传完成后,调用AG Grid API强制刷新当前单元格:
async onFileSelected(event: any, invoice: Invoice): Promise<void> { let componentParent = this.params.context.componentParent; const file: File = event.target.files[0]; const response: string = await this.documentsService.handleDocumentUpload(file, invoice.id); if (response != null && response !== '') { await this.updateInvoiceResponse(invoice.id, componentParent.invoiceResponse); // 刷新当前单元格 componentParent.gridApi?.refreshCells({ rowNodes: [this.params.node], columns: [this.params.column.getId()], force: true // 强制刷新,忽略缓存 }); } }
4. 优化共享服务的Subject类型
将Subject替换为BehaviorSubject,确保初始值和更新都能被正确订阅,同时每次发送新数组:
@Injectable({ providedIn: 'root' }) export class InvoiceService { private _searchInvoiceResponse: BehaviorSubject<Invoice[]> = new BehaviorSubject<Invoice[]>([]); invoicesResponse$(): Observable<Invoice[]> { return this._searchInvoiceResponse.asObservable(); } setSearchInvoicesResponse(invoices: Invoice[]): void { // 每次发送新数组副本 this._searchInvoiceResponse.next([...invoices]); } }
总结
以上方法可组合使用,核心是让AG Grid感知到数据变化,并确保单元格渲染器能响应数据更新。优先保证数据不可变性,再结合Grid API的刷新逻辑,即可解决按钮状态不自动更新的问题。
内容的提问来源于stack exchange,提问作者SEED
相关产品推荐
相关产品推荐

