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

如何在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 08:19:56