@cdmx/wappler_ag_grid 2.0.12 → 2.0.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +4 -0
  2. package/dmx-ag-grid.js +208 -118
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -609,6 +609,10 @@ You can also specify left-only conditions, where only the field name is provided
609
609
  **Export**
610
610
  - To be used if you wish to use a separate Export button instead of using the inbuilt top left-cornered Export button.
611
611
  - Trigger this action to call Export Data to CSV/PDF download action based on selected file Type.
612
+ - **Column State Integration**: When exporting data, the grid automatically respects the saved column state from localStorage. This means:
613
+ - Columns are exported in the same order as they appear in the grid (based on user's saved column arrangement)
614
+ - Hidden columns are automatically excluded from export
615
+ - If no saved column state exists, the export falls back to the default column configuration
612
616
 
613
617
  **Save Column State**
614
618
  - This action allows you to save the current state of the grid's columns, including their visibility and order, to the browser's local storage.
package/dmx-ag-grid.js CHANGED
@@ -356,9 +356,11 @@ dmx.Component('ag-grid', {
356
356
  Csv = true;
357
357
  }
358
358
  dmx.nextTick(() => {
359
- const exportFunction = Csv ? exportGridData : (Pdf ? exportGridDataToPDF : null);
360
- if (typeof exportFunction === 'function') {
361
- exportFunction();
359
+ const gridInst = this.get('gridInstance');
360
+ if (Csv) {
361
+ exportGridData(gridInst, this.gridConfig);
362
+ } else if (Pdf) {
363
+ exportGridDataToPDF(gridInst, this.gridConfig);
362
364
  } else {
363
365
  console.error('Grid not loaded to perform the requested export');
364
366
  }
@@ -1979,6 +1981,8 @@ dmx.Component('ag-grid', {
1979
1981
  columnDefs: columnDefs,
1980
1982
  ...gridOptions
1981
1983
  };
1984
+ // Store gridConfig on component instance for export functions
1985
+ this.gridConfig = gridConfig;
1982
1986
  // Conditionally add event listeners based on whether columnsToSum or columnsToCount are defined
1983
1987
  if ((options.columns_to_sum && options.columns_to_sum.split(',').length > 0) || (options.columns_to_count.length > 0)) {
1984
1988
  let columnsToSum = options.columns_to_sum ? options.columns_to_sum.split(',') : [];
@@ -2150,42 +2154,107 @@ dmx.Component('ag-grid', {
2150
2154
  updateHoveringBarStyles();
2151
2155
 
2152
2156
  //CSV Export Function
2153
- exportGridData = () => {
2157
+ exportGridData = (currentGridInstance, currentGridConfig) => {
2154
2158
  const excludedColumnIds = ['checkboxColumn', 'actionsColumn'];
2155
2159
  const exportExcludeFieldsArray = options.export_exclude_fields ? options.export_exclude_fields.split(',') : [];
2156
- // Extracting fields and colIds from columnDefs
2157
- let fieldsAndColIds;
2158
- if (options.group_config) {
2159
- // Helper function to traverse grouped column structure
2160
- const traverseColumns = (columns) => {
2161
- const fieldsAndColIds = [];
2162
- columns.forEach((column) => {
2163
- if (column.children) {
2164
- fieldsAndColIds.push(...traverseColumns(column.children));
2165
- } else {
2166
- fieldsAndColIds.push({
2167
- field: column.field,
2168
- colId: column.colId,
2169
- hide: column.hide,
2170
- });
2160
+
2161
+ let fieldsToExport = [];
2162
+
2163
+ // Try to get saved column state from localStorage
2164
+ const pageId = getPageId();
2165
+ const storageKey = options.column_state_storage_key || pageId;
2166
+ const savedColumnState = localStorage.getItem(`dmxState-${storageKey}`);
2167
+
2168
+ // If saved column state exists, use it
2169
+ if (savedColumnState) {
2170
+ try {
2171
+ const parsedState = JSON.parse(savedColumnState);
2172
+ // Use the saved state to determine column order and visibility
2173
+ fieldsToExport = parsedState
2174
+ .filter((col) => {
2175
+ // Skip excluded columns
2176
+ if (excludedColumnIds.includes(col.colId)) {
2177
+ return false;
2178
+ }
2179
+ // Skip hidden columns (respecting the hide property from saved state)
2180
+ if (col.hide) {
2181
+ return false;
2182
+ }
2183
+ return true;
2184
+ })
2185
+ .map((col) => {
2186
+ // Map colId to field from columnDefs
2187
+ const columnDef = findColumnDefByColId(col.colId);
2188
+ return columnDef ? columnDef.field : col.colId;
2189
+ })
2190
+ .filter((field) => !exportExcludeFieldsArray.includes(field));
2191
+ } catch (err) {
2192
+ console.warn(`Failed to parse saved column state for key: dmxState-${storageKey}`, err);
2193
+ fieldsToExport = [];
2194
+ }
2195
+ }
2196
+
2197
+ // Helper function to find column definition by colId
2198
+ function findColumnDefByColId(colId) {
2199
+ if (options.group_config) {
2200
+ const traverseColumns = (columns) => {
2201
+ for (const column of columns) {
2202
+ if (column.children) {
2203
+ const result = traverseColumns(column.children);
2204
+ if (result) return result;
2205
+ } else if (column.colId === colId) {
2206
+ return column;
2207
+ }
2171
2208
  }
2172
- });
2173
- return fieldsAndColIds;
2174
- };
2175
- // Traverse columnDefs to gather fields and colIds
2176
- fieldsAndColIds = traverseColumns(gridConfig.columnDefs);
2177
- } else {
2178
- fieldsAndColIds = gridConfig.columnDefs.map((column) => ({
2179
- field: column.field,
2180
- colId: column.colId,
2181
- hide: column.hide,
2182
- }));
2209
+ return null;
2210
+ };
2211
+ return traverseColumns(currentGridConfig.columnDefs);
2212
+ } else {
2213
+ return currentGridConfig.columnDefs.find((column) => column.colId === colId);
2214
+ }
2215
+ }
2216
+
2217
+ // Fallback to current logic if no saved state or if fieldsToExport is empty
2218
+ if (!fieldsToExport || fieldsToExport.length === 0) {
2219
+ fieldsToExport = getDefaultExportFields();
2220
+ }
2221
+
2222
+ function getDefaultExportFields() {
2223
+ // Extracting fields and colIds from columnDefs
2224
+ let fieldsAndColIds;
2225
+ if (options.group_config) {
2226
+ // Helper function to traverse grouped column structure
2227
+ const traverseColumns = (columns) => {
2228
+ const fieldsAndColIds = [];
2229
+ columns.forEach((column) => {
2230
+ if (column.children) {
2231
+ fieldsAndColIds.push(...traverseColumns(column.children));
2232
+ } else {
2233
+ fieldsAndColIds.push({
2234
+ field: column.field,
2235
+ colId: column.colId,
2236
+ hide: column.hide,
2237
+ });
2238
+ }
2239
+ });
2240
+ return fieldsAndColIds;
2241
+ };
2242
+ // Traverse columnDefs to gather fields and colIds
2243
+ fieldsAndColIds = traverseColumns(currentGridConfig.columnDefs);
2244
+ } else {
2245
+ fieldsAndColIds = currentGridConfig.columnDefs.map((column) => ({
2246
+ field: column.field,
2247
+ colId: column.colId,
2248
+ hide: column.hide,
2249
+ }));
2250
+ }
2251
+ const result = fieldsAndColIds.filter((column) => {
2252
+ return !excludedColumnIds.includes(column.colId) &&
2253
+ (!options.export_exclude_hidden_fields || !column.hide) &&
2254
+ !exportExcludeFieldsArray.includes(column.field);
2255
+ }).map((column) => column.field);
2256
+ return result;
2183
2257
  }
2184
- const fieldsToExport = fieldsAndColIds.filter((column) => {
2185
- return !excludedColumnIds.includes(column.colId) &&
2186
- (!options.export_exclude_hidden_fields || !column.hide) &&
2187
- !exportExcludeFieldsArray.includes(column.field);
2188
- }).map((column) => column.field);
2189
2258
 
2190
2259
  const params = {
2191
2260
  fileName: options.export_csv_filename,
@@ -2226,46 +2295,57 @@ dmx.Component('ag-grid', {
2226
2295
  return value;
2227
2296
  },
2228
2297
  };
2229
- gridInstance.exportDataAsCsv(params);
2298
+ currentGridInstance.exportDataAsCsv(params);
2230
2299
  };
2231
2300
  // Create the export button
2232
2301
  if (exportToCSV) {
2233
- const existingExportButton = document.getElementById('exportButton');
2234
- if (existingExportButton) {
2235
- return;
2236
- }
2237
- const exportButton = document.createElement('button');
2238
- exportButton.id = 'exportButton';
2239
- const icon = document.createElement('i');
2240
- icon.classList.add('fas', 'fa-file-csv');
2241
- exportButton.appendChild(icon);
2302
+ let exportButton = document.getElementById(`exportButton-${options.id}`);
2303
+ let isNewButton = false;
2304
+ if (!exportButton) {
2305
+ isNewButton = true;
2306
+ exportButton = document.createElement('button');
2307
+ exportButton.id = `exportButton-${options.id}`;
2308
+ const icon = document.createElement('i');
2309
+ icon.classList.add('fas', 'fa-file-csv');
2310
+ exportButton.appendChild(icon);
2242
2311
 
2243
- // Add the button text
2244
- const buttonText = document.createElement('span');
2245
- buttonText.innerText = ' Export to CSV';
2246
- exportButton.appendChild(buttonText);
2247
- exportButton.style.backgroundColor = '#4CAF50';
2248
- exportButton.style.border = 'none';
2249
- exportButton.style.color = 'white';
2250
- exportButton.style.padding = '5px 10px';
2251
- exportButton.style.textAlign = 'center';
2252
- exportButton.style.textDecoration = 'none';
2253
- exportButton.style.display = 'inline-block';
2254
- exportButton.style.fontSize = '14px';
2255
- exportButton.style.borderRadius = '5px';
2256
- exportButton.style.cursor = 'pointer';
2257
- exportButton.style.marginBottom = '10px';
2258
-
2259
- exportButton.addEventListener('click', () => {
2260
- exportGridData()
2261
- })
2262
- // Append the export button to the grid container
2263
- gridContainer.parentNode.insertBefore(exportButton, gridContainer);
2264
- exportButton.style.marginBottom = '10px';
2312
+ // Add the button text
2313
+ const buttonText = document.createElement('span');
2314
+ buttonText.innerText = ' Export to CSV';
2315
+ exportButton.appendChild(buttonText);
2316
+ exportButton.style.backgroundColor = '#4CAF50';
2317
+ exportButton.style.border = 'none';
2318
+ exportButton.style.color = 'white';
2319
+ exportButton.style.padding = '5px 10px';
2320
+ exportButton.style.textAlign = 'center';
2321
+ exportButton.style.textDecoration = 'none';
2322
+ exportButton.style.display = 'inline-block';
2323
+ exportButton.style.fontSize = '14px';
2324
+ exportButton.style.borderRadius = '5px';
2325
+ exportButton.style.cursor = 'pointer';
2326
+ exportButton.style.marginBottom = '10px';
2327
+ }
2328
+
2329
+ // Always update the click handler to ensure it has the latest gridInstance and gridConfig
2330
+ exportButton.onclick = () => {
2331
+ const currentGridInstance = this.get('gridInstance');
2332
+ const currentGridConfig = this.gridConfig;
2333
+ if (currentGridInstance && currentGridConfig) {
2334
+ exportGridData(currentGridInstance, currentGridConfig);
2335
+ } else {
2336
+ console.error('Grid instance or configuration not available for export');
2337
+ }
2338
+ };
2339
+
2340
+ if (isNewButton) {
2341
+ // Append the export button to the grid container
2342
+ gridContainer.parentNode.insertBefore(exportButton, gridContainer);
2343
+ exportButton.style.marginBottom = '10px';
2344
+ }
2265
2345
  }
2266
2346
  // Export AG Grid data to PDF
2267
- exportGridDataToPDF = async () => {
2268
- if (!gridInstance || gridInstance.isDestroyed()) {
2347
+ exportGridDataToPDF = async (currentGridInstance, currentGridConfig) => {
2348
+ if (!currentGridInstance || currentGridInstance.isDestroyed()) {
2269
2349
  console.error('Grid API is destroyed or not initialized.');
2270
2350
  return;
2271
2351
  }
@@ -2290,9 +2370,9 @@ dmx.Component('ag-grid', {
2290
2370
  return fieldsAndColIds;
2291
2371
  };
2292
2372
  // Traverse columnDefs to gather fields and colIds
2293
- fieldsAndColIds = traverseColumns(gridConfig.columnDefs);
2373
+ fieldsAndColIds = traverseColumns(currentGridConfig.columnDefs);
2294
2374
  } else {
2295
- fieldsAndColIds = gridConfig.columnDefs.map((column) => ({
2375
+ fieldsAndColIds = currentGridConfig.columnDefs.map((column) => ({
2296
2376
  field: column.field,
2297
2377
  colId: column.colId,
2298
2378
  hide: column.hide,
@@ -2344,19 +2424,19 @@ dmx.Component('ag-grid', {
2344
2424
  return options.wrap_text ? { whiteSpace: 'normal' } : null;
2345
2425
  };
2346
2426
 
2347
- const getColumnData = (gridInstance, isHeader) =>
2348
- gridInstance.getAllDisplayedColumns()
2427
+ const getColumnData = (gInstance, isHeader) =>
2428
+ gInstance.getAllDisplayedColumns()
2349
2429
  .filter(column => fieldsToExport.includes(column.getColDef().field))
2350
2430
  .map(column => {
2351
2431
  const colDef = column.getColDef();
2352
2432
  const field = colDef.field;
2353
2433
  const params = {
2354
- value: isHeader ? null : gridInstance.getValue(column, gridInstance.getDisplayedRowAtIndex(0)),
2355
- data: isHeader ? null : gridInstance.getDisplayedRowAtIndex(0).data,
2356
- node: isHeader ? null : gridInstance.getDisplayedRowAtIndex(0),
2434
+ value: isHeader ? null : gInstance.getValue(column, gInstance.getDisplayedRowAtIndex(0)),
2435
+ data: isHeader ? null : gInstance.getDisplayedRowAtIndex(0).data,
2436
+ node: isHeader ? null : gInstance.getDisplayedRowAtIndex(0),
2357
2437
  colDef,
2358
2438
  column,
2359
- api: gridInstance,
2439
+ api: gInstance,
2360
2440
  context: params.context,
2361
2441
  };
2362
2442
  const cellStyle = applyCellStyle(params);
@@ -2370,31 +2450,31 @@ dmx.Component('ag-grid', {
2370
2450
  text: !isHeader ? (
2371
2451
  (colDef.cellRenderer && typeof colDef.cellRenderer === 'function') ? colDef.cellRenderer(params) :
2372
2452
  (colDef.valueFormatter && typeof colDef.valueFormatter === 'function') ? colDef.valueFormatter(params) :
2373
- gridInstance.getValue(column, gridInstance.getDisplayedRowAtIndex(0)) ?? ''
2453
+ gInstance.getValue(column, gInstance.getDisplayedRowAtIndex(0)) ?? ''
2374
2454
  ) : headerName,
2375
2455
  color: cellStyle?.color ?? 'black',
2376
2456
  fillColor: cellStyle?.backgroundColor ? cellStyle.backgroundColor.replace('#', '') : undefined,
2377
2457
  };
2378
- });
2458
+ });;
2379
2459
 
2380
- const columns = gridInstance.getColumnState();
2460
+ const columns = currentGridInstance.getColumnState();
2381
2461
  const columnMap = new Map(columns.map(col => [col.colId, col]));
2382
2462
 
2383
2463
  const rows = [];
2384
- gridInstance.forEachNode(node => {
2464
+ currentGridInstance.forEachNode(node => {
2385
2465
  const row = fieldsToExport.map(field => {
2386
2466
  const col = columnMap.get(field);
2387
- const colDef = col ? gridInstance.getColumnDefs().find(def => def.colId === col.colId) : {};
2467
+ const colDef = col ? currentGridInstance.getColumnDefs().find(def => def.colId === col.colId) : {};
2388
2468
  const params = {
2389
- value: gridInstance.getCellValue({ rowNode: node, colKey: col.colId }) ?? '-',
2469
+ value: currentGridInstance.getCellValue({ rowNode: node, colKey: col.colId }) ?? '-',
2390
2470
  data: node.data,
2391
2471
  node,
2392
2472
  colDef,
2393
- column: gridInstance.getColumnState().find(col => col.colId === col.colId),
2394
- api: gridInstance,
2473
+ column: currentGridInstance.getColumnState().find(col => col.colId === col.colId),
2474
+ api: currentGridInstance,
2395
2475
  };
2396
2476
  const cellStyle = applyCellStyle(params);
2397
- const value = gridInstance.getCellValue({ rowNode: node, colKey: col.colId }) ?? '-';
2477
+ const value = currentGridInstance.getCellValue({ rowNode: node, colKey: col.colId }) ?? '-';
2398
2478
  return {
2399
2479
  text: (colDef.cellRenderer && typeof colDef.cellRenderer === 'function') ? colDef.cellRenderer(params) :
2400
2480
  (colDef.valueFormatter && typeof colDef.valueFormatter === 'function') ? colDef.valueFormatter(params) :
@@ -2411,7 +2491,7 @@ dmx.Component('ag-grid', {
2411
2491
  table: {
2412
2492
  headerRows: 1,
2413
2493
  widths: fieldsToExport.map(() => `${100 / fieldsToExport.length}%`),
2414
- body: [getColumnData(gridInstance, true), ...rows],
2494
+ body: [getColumnData(currentGridInstance, true), ...rows],
2415
2495
  heights: (rowIndex) => (rowIndex === 0 ? 40 : 15),
2416
2496
  fillColor: (rowIndex, colIndex) => rows[rowIndex][colIndex].fillColor,
2417
2497
  color: (rowIndex, colIndex) => rows[rowIndex][colIndex].color,
@@ -2421,39 +2501,49 @@ dmx.Component('ag-grid', {
2421
2501
  pdfMake.createPdf(documentDefinition).download(options.export_pdf_filename);
2422
2502
  };
2423
2503
  if (exportToPDF) {
2424
- const existingPdfExportButton = document.getElementById('exportPdfButton');
2425
- if (existingPdfExportButton) {
2426
- return;
2427
- }
2428
- const exportPdfButton = document.createElement('button');
2429
- exportPdfButton.id = 'exportPdfButton';
2430
- const icon = document.createElement('i');
2431
- icon.classList.add('fas', 'fa-file-pdf');
2432
- exportPdfButton.appendChild(icon);
2433
-
2434
- // Add the button text
2435
- const buttonText = document.createElement('span');
2436
- buttonText.innerText = ' Export to PDF';
2437
- exportPdfButton.appendChild(buttonText);
2438
- exportPdfButton.style.backgroundColor = '#4CAF50';
2439
- exportPdfButton.style.border = 'none';
2440
- exportPdfButton.style.color = 'white';
2441
- exportPdfButton.style.padding = '5px 10px';
2442
- exportPdfButton.style.textAlign = 'center';
2443
- exportPdfButton.style.textDecoration = 'none';
2444
- exportPdfButton.style.display = 'inline-block';
2445
- exportPdfButton.style.fontSize = '14px';
2446
- exportPdfButton.style.borderRadius = '5px';
2447
- exportPdfButton.style.cursor = 'pointer';
2448
- exportPdfButton.style.marginBottom = '10px';
2504
+ let exportPdfButton = document.getElementById(`exportPdfButton-${options.id}`);
2505
+ let isNewPdfButton = false;
2506
+ if (!exportPdfButton) {
2507
+ isNewPdfButton = true;
2508
+ exportPdfButton = document.createElement('button');
2509
+ exportPdfButton.id = `exportPdfButton-${options.id}`;
2510
+ const icon = document.createElement('i');
2511
+ icon.classList.add('fas', 'fa-file-pdf');
2512
+ exportPdfButton.appendChild(icon);
2449
2513
 
2450
- exportPdfButton.addEventListener('click', () => {
2451
- exportGridDataToPDF(this)
2452
- })
2514
+ // Add the button text
2515
+ const buttonText = document.createElement('span');
2516
+ buttonText.innerText = ' Export to PDF';
2517
+ exportPdfButton.appendChild(buttonText);
2518
+ exportPdfButton.style.backgroundColor = '#4CAF50';
2519
+ exportPdfButton.style.border = 'none';
2520
+ exportPdfButton.style.color = 'white';
2521
+ exportPdfButton.style.padding = '5px 10px';
2522
+ exportPdfButton.style.textAlign = 'center';
2523
+ exportPdfButton.style.textDecoration = 'none';
2524
+ exportPdfButton.style.display = 'inline-block';
2525
+ exportPdfButton.style.fontSize = '14px';
2526
+ exportPdfButton.style.borderRadius = '5px';
2527
+ exportPdfButton.style.cursor = 'pointer';
2528
+ exportPdfButton.style.marginBottom = '10px';
2529
+ }
2530
+
2531
+ // Always update the click handler to ensure it has the latest gridInstance and gridConfig
2532
+ exportPdfButton.onclick = () => {
2533
+ const currentGridInstance = this.get('gridInstance');
2534
+ const currentGridConfig = this.gridConfig;
2535
+ if (currentGridInstance && currentGridConfig) {
2536
+ exportGridDataToPDF(currentGridInstance, currentGridConfig);
2537
+ } else {
2538
+ console.error('Grid instance or configuration not available for export');
2539
+ }
2540
+ };
2453
2541
 
2454
- // Append the export button to the grid container
2455
- gridContainer.parentNode.insertBefore(exportPdfButton, gridContainer);
2456
- exportPdfButton.style.marginBottom = '10px';
2542
+ if (isNewPdfButton) {
2543
+ // Append the export button to the grid container
2544
+ gridContainer.parentNode.insertBefore(exportPdfButton, gridContainer);
2545
+ exportPdfButton.style.marginBottom = '10px';
2546
+ }
2457
2547
  }
2458
2548
  const paginationPanelCss = `
2459
2549
  /* Flexbox layout for pagination panel */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cdmx/wappler_ag_grid",
3
- "version": "2.0.12",
3
+ "version": "2.0.14",
4
4
  "type": "module",
5
5
  "description": "App Connect module for AG Grid v34 - Advanced data grid with enhanced editing, filtering, and tree data capabilities.",
6
6
  "license": "MIT",