如何在Node.js中为不同用户生成独立的AG-Grid表格?
解决方案:避免AG-Grid静态JS文件被覆盖,实现用户专属数据渲染
核心问题分析
你当前通过后端生成静态JS文件的方式,本质是所有用户共享同一个文件,多用户并发操作时必然会出现数据覆盖。解决思路是让每个用户的页面加载时获取专属的配置和数据,而非依赖全局静态文件。
方案一:通过Handlebars模板直接注入用户数据
后端修改(Node.js + Express + Handlebars)
不再生成静态JS文件,而是在路由中获取当前用户的数据,将配置和数据序列化后传给Handlebars模板:
// 路由处理函数 app.get('/members', async (req, res) => { // 替换为你的业务逻辑:获取当前用户对应的成员数据 const rowData = await getMembersForCurrentUser(req.user.id); // 抽离公共列配置(可单独放在模块文件中复用) const columnDefs = [ { headerName: 'Nombre', field: 'nombre', filter: 'agTextColumnFilter' }, { headerName: 'Correo Electrónico', field: 'correo', cellRenderer: (params) => `<a target='_blank' href='mailto:${params.data.correo}'>${params.data.correo}</a>` }, { headerName: 'Empresa', field: 'empresa', filter: 'agSetColumnFilter' } ]; // 渲染模板并传递序列化后的配置和数据 res.render('members', { rowData: JSON.stringify(rowData), columnDefs: JSON.stringify(columnDefs) }); });
前端Handlebars模板修改
在模板中直接使用注入的数据初始化AG-Grid,无需引入静态JS文件:
<div id="myGrid" style="height: 100%; width: 100%;"></div> <select id="pageSizeSelect" onchange="changePageSizeFunction()"> <option value="15">15 por página</option> <option value="30">30 por página</option> <option value="-1">Todos</option> </select> <script src="https://cdn.jsdelivr.net/npm/ag-grid-community/dist/ag-grid-community.min.js"></script> <script> // 从模板注入的用户专属数据和列配置 const rowData = {{rowData}}; const columnDefs = {{columnDefs}}; let gridOptions; function initGrid() { gridOptions = { columnDefs: columnDefs, defaultColDef: { flex: 1, minWidth: 150, resizable: true, enableValue: true, enableRowGroup: true, sortable: true }, animateRows: true, rowData: rowData, pagination: true, paginationPageSize: 15, domLayout: 'autoHeight', enableSorting: true, enableFilter: true }; const eGridDiv = document.querySelector('#myGrid'); new agGrid.Grid(eGridDiv, gridOptions); // 许可证密钥可抽离到公共JS文件中 agGrid.LicenseManager.setLicenseKey('[TRIAL]_this_AG_Grid_Enterprise_key_( AG-043903 )_is_granted_for_evaluation_only___Use_in_production_is_not_permitted___Please_report_misuse_to_( legal@ag-grid.com )___For_help_with_purchasing_a_production_key_please_contact_( info@ag-grid.com )___All_Front-End_JavaScript_developers_working_on_the_application_would_need_to_be_licensed___This_key_will_deactivate_on_( 30 September 2023 )____[v2]_MTY5NjAyODQwMDAwMA==4a43d539f6521489ef3e796e6a5d1d09'); } function changePageSizeFunction() { const pageSizeSelect = document.getElementById('pageSizeSelect'); const selectedPageSize = parseInt(pageSizeSelect.value, 10); if (selectedPageSize === -1) { gridOptions.api.paginationSetPageSize(Number.MAX_VALUE); } else { gridOptions.api.paginationSetPageSize(selectedPageSize); } } // 页面加载完成后初始化表格 document.addEventListener('DOMContentLoaded', initGrid); </script>
方案二:前端异步请求用户数据(更高效灵活)
如果数据量较大或需要动态更新,推荐通过API异步获取数据,减少模板渲染压力:
后端新增API路由
app.get('/api/members', async (req, res) => { // 验证用户权限后返回专属数据 const rowData = await getMembersForCurrentUser(req.user.id); res.json(rowData); });
前端修改
列配置直接写在前端(或抽离到公共JS),页面加载时异步请求数据:
<div id="myGrid" style="height: 100%; width: 100%;"></div> <select id="pageSizeSelect" onchange="changePageSizeFunction()"> <option value="15">15 por página</option> <option value="30">30 por página</option> <option value="-1">Todos</option> </select> <script src="https://cdn.jsdelivr.net/npm/ag-grid-community/dist/ag-grid-community.min.js"></script> <script> // 公共列配置(可抽离到单独JS文件) const columnDefs = [ { headerName: 'Nombre', field: 'nombre', filter: 'agTextColumnFilter' }, { headerName: 'Correo Electrónico', field: 'correo', cellRenderer: (params) => `<a target='_blank' href='mailto:${params.data.correo}'>${params.data.correo}</a>` }, { headerName: 'Empresa', field: 'empresa', filter: 'agSetColumnFilter' } ]; let gridOptions; async function initGrid() { // 异步请求当前用户的数据 const response = await fetch('/api/members'); const rowData = await response.json(); gridOptions = { columnDefs: columnDefs, defaultColDef: { flex: 1, minWidth: 150, resizable: true, enableValue: true, enableRowGroup: true, sortable: true }, animateRows: true, rowData: rowData, pagination: true, paginationPageSize: 15, domLayout: 'autoHeight', enableSorting: true, enableFilter: true }; const eGridDiv = document.querySelector('#myGrid'); new agGrid.Grid(eGridDiv, gridOptions); agGrid.LicenseManager.setLicenseKey('[TRIAL]_this_AG_Grid_Enterprise_key_( AG-043903 )_is_granted_for_evaluation_only___Use_in_production_is_not_permitted___Please_report_misuse_to_( legal@ag-grid.com )___For_help_with_purchasing_a_production_key_please_contact_( info@ag-grid.com )___All_Front-End_JavaScript_developers_working_on_the_application_would_need_to_be_licensed___This_key_will_deactivate_on_( 30 September 2023 )____[v2]_MTY5NjAyODQwMDAwMA==4a43d539f6521489ef3e796e6a5d1d09'); } function changePageSizeFunction() { const pageSizeSelect = document.getElementById('pageSizeSelect'); const selectedPageSize = parseInt(pageSizeSelect.value, 10); if (selectedPageSize === -1) { gridOptions.api.paginationSetPageSize(Number.MAX_VALUE); } else { gridOptions.api.paginationSetPageSize(selectedPageSize); } } document.addEventListener('DOMContentLoaded', initGrid); </script>
方案对比
| 方案类型 | 优点 | 适用场景 |
|---|---|---|
| 模板注入数据 | 无需额外API请求,页面加载即显示表格 | 数据量小、需快速渲染场景 |
| 异步API请求 | 支持后端分页/筛选,灵活度高,易维护 | 数据量大、需动态更新场景 |
内容的提问来源于stack exchange,提问作者Khakovs
相关产品推荐
相关产品推荐

