@cdmx/wappler_ag_grid 2.0.13 → 2.0.15

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.
@@ -253,6 +253,14 @@
253
253
  "type": "text",
254
254
  "help": "Specifies fields to be excluded in CSV export (comma-seperated)."
255
255
  },
256
+ {
257
+ "name": "exportRemoveHtml",
258
+ "attribute": "dmx-bind:export_remove_html",
259
+ "title": "Remove HTML from Export",
260
+ "type": "boolean",
261
+ "defaultValue": false,
262
+ "help": "Removes HTML tags from exported data (CSV/PDF). Converts <br> tags to newlines."
263
+ },
256
264
  {
257
265
  "name": "paginationPageSizeSelector",
258
266
  "attribute": "dmx-bind:pagination_page_size_selector",
package/dmx-ag-grid.js CHANGED
@@ -87,6 +87,7 @@ dmx.Component('ag-grid', {
87
87
  export_trim_data: { type: Boolean, default: false },
88
88
  export_exclude_hidden_fields: { type: Boolean, default: false },
89
89
  export_exclude_fields: { type: String, default: null },
90
+ export_remove_html: { type: Boolean, default: false },
90
91
  export_to_csv: { type: Boolean, default: true },
91
92
  export_csv_filename: { type: String, default: 'export.csv' },
92
93
  export_to_pdf: { type: Boolean, default: false },
@@ -356,9 +357,11 @@ dmx.Component('ag-grid', {
356
357
  Csv = true;
357
358
  }
358
359
  dmx.nextTick(() => {
359
- const exportFunction = Csv ? exportGridData : (Pdf ? exportGridDataToPDF : null);
360
- if (typeof exportFunction === 'function') {
361
- exportFunction();
360
+ const gridInst = this.get('gridInstance');
361
+ if (Csv) {
362
+ exportGridData(gridInst, this.gridConfig);
363
+ } else if (Pdf) {
364
+ exportGridDataToPDF(gridInst, this.gridConfig);
362
365
  } else {
363
366
  console.error('Grid not loaded to perform the requested export');
364
367
  }
@@ -1979,6 +1982,8 @@ dmx.Component('ag-grid', {
1979
1982
  columnDefs: columnDefs,
1980
1983
  ...gridOptions
1981
1984
  };
1985
+ // Store gridConfig on component instance for export functions
1986
+ this.gridConfig = gridConfig;
1982
1987
  // Conditionally add event listeners based on whether columnsToSum or columnsToCount are defined
1983
1988
  if ((options.columns_to_sum && options.columns_to_sum.split(',').length > 0) || (options.columns_to_count.length > 0)) {
1984
1989
  let columnsToSum = options.columns_to_sum ? options.columns_to_sum.split(',') : [];
@@ -2150,7 +2155,22 @@ dmx.Component('ag-grid', {
2150
2155
  updateHoveringBarStyles();
2151
2156
 
2152
2157
  //CSV Export Function
2153
- exportGridData = () => {
2158
+ // Helper function to remove HTML tags from string
2159
+ const removeHtmlTags = (htmlString) => {
2160
+ if (typeof htmlString !== 'string') return htmlString;
2161
+ // Remove all HTML tags and decode common HTML entities
2162
+ return htmlString
2163
+ .replace(/<br\s*\/?>/gi, '\n') // Replace <br> tags with newlines
2164
+ .replace(/<[^>]*>/g, '') // Remove all other HTML tags
2165
+ .replace(/&nbsp;/g, ' ') // Replace non-breaking space
2166
+ .replace(/&lt;/g, '<')
2167
+ .replace(/&gt;/g, '>')
2168
+ .replace(/&amp;/g, '&')
2169
+ .replace(/&quot;/g, '"')
2170
+ .replace(/&#39;/g, "'");
2171
+ };
2172
+
2173
+ exportGridData = (currentGridInstance, currentGridConfig) => {
2154
2174
  const excludedColumnIds = ['checkboxColumn', 'actionsColumn'];
2155
2175
  const exportExcludeFieldsArray = options.export_exclude_fields ? options.export_exclude_fields.split(',') : [];
2156
2176
 
@@ -2204,9 +2224,9 @@ dmx.Component('ag-grid', {
2204
2224
  }
2205
2225
  return null;
2206
2226
  };
2207
- return traverseColumns(gridConfig.columnDefs);
2227
+ return traverseColumns(currentGridConfig.columnDefs);
2208
2228
  } else {
2209
- return gridConfig.columnDefs.find((column) => column.colId === colId);
2229
+ return currentGridConfig.columnDefs.find((column) => column.colId === colId);
2210
2230
  }
2211
2231
  }
2212
2232
 
@@ -2236,9 +2256,9 @@ dmx.Component('ag-grid', {
2236
2256
  return fieldsAndColIds;
2237
2257
  };
2238
2258
  // Traverse columnDefs to gather fields and colIds
2239
- fieldsAndColIds = traverseColumns(gridConfig.columnDefs);
2259
+ fieldsAndColIds = traverseColumns(currentGridConfig.columnDefs);
2240
2260
  } else {
2241
- fieldsAndColIds = gridConfig.columnDefs.map((column) => ({
2261
+ fieldsAndColIds = currentGridConfig.columnDefs.map((column) => ({
2242
2262
  field: column.field,
2243
2263
  colId: column.colId,
2244
2264
  hide: column.hide,
@@ -2283,6 +2303,11 @@ dmx.Component('ag-grid', {
2283
2303
  }
2284
2304
  }
2285
2305
 
2306
+ // Remove HTML tags if export_remove_html is true
2307
+ if (options.export_remove_html && typeof value === 'string') {
2308
+ value = removeHtmlTags(value);
2309
+ }
2310
+
2286
2311
  // Trim value if export_trim is true
2287
2312
  if (options.export_trim_data && typeof value === 'string') {
2288
2313
  return value.trim();
@@ -2291,46 +2316,57 @@ dmx.Component('ag-grid', {
2291
2316
  return value;
2292
2317
  },
2293
2318
  };
2294
- gridInstance.exportDataAsCsv(params);
2319
+ currentGridInstance.exportDataAsCsv(params);
2295
2320
  };
2296
2321
  // Create the export button
2297
2322
  if (exportToCSV) {
2298
- const existingExportButton = document.getElementById('exportButton');
2299
- if (existingExportButton) {
2300
- return;
2301
- }
2302
- const exportButton = document.createElement('button');
2303
- exportButton.id = 'exportButton';
2304
- const icon = document.createElement('i');
2305
- icon.classList.add('fas', 'fa-file-csv');
2306
- exportButton.appendChild(icon);
2323
+ let exportButton = document.getElementById(`exportButton-${options.id}`);
2324
+ let isNewButton = false;
2325
+ if (!exportButton) {
2326
+ isNewButton = true;
2327
+ exportButton = document.createElement('button');
2328
+ exportButton.id = `exportButton-${options.id}`;
2329
+ const icon = document.createElement('i');
2330
+ icon.classList.add('fas', 'fa-file-csv');
2331
+ exportButton.appendChild(icon);
2307
2332
 
2308
- // Add the button text
2309
- const buttonText = document.createElement('span');
2310
- buttonText.innerText = ' Export to CSV';
2311
- exportButton.appendChild(buttonText);
2312
- exportButton.style.backgroundColor = '#4CAF50';
2313
- exportButton.style.border = 'none';
2314
- exportButton.style.color = 'white';
2315
- exportButton.style.padding = '5px 10px';
2316
- exportButton.style.textAlign = 'center';
2317
- exportButton.style.textDecoration = 'none';
2318
- exportButton.style.display = 'inline-block';
2319
- exportButton.style.fontSize = '14px';
2320
- exportButton.style.borderRadius = '5px';
2321
- exportButton.style.cursor = 'pointer';
2322
- exportButton.style.marginBottom = '10px';
2323
-
2324
- exportButton.addEventListener('click', () => {
2325
- exportGridData()
2326
- })
2327
- // Append the export button to the grid container
2328
- gridContainer.parentNode.insertBefore(exportButton, gridContainer);
2329
- exportButton.style.marginBottom = '10px';
2333
+ // Add the button text
2334
+ const buttonText = document.createElement('span');
2335
+ buttonText.innerText = ' Export to CSV';
2336
+ exportButton.appendChild(buttonText);
2337
+ exportButton.style.backgroundColor = '#4CAF50';
2338
+ exportButton.style.border = 'none';
2339
+ exportButton.style.color = 'white';
2340
+ exportButton.style.padding = '5px 10px';
2341
+ exportButton.style.textAlign = 'center';
2342
+ exportButton.style.textDecoration = 'none';
2343
+ exportButton.style.display = 'inline-block';
2344
+ exportButton.style.fontSize = '14px';
2345
+ exportButton.style.borderRadius = '5px';
2346
+ exportButton.style.cursor = 'pointer';
2347
+ exportButton.style.marginBottom = '10px';
2348
+ }
2349
+
2350
+ // Always update the click handler to ensure it has the latest gridInstance and gridConfig
2351
+ exportButton.onclick = () => {
2352
+ const currentGridInstance = this.get('gridInstance');
2353
+ const currentGridConfig = this.gridConfig;
2354
+ if (currentGridInstance && currentGridConfig) {
2355
+ exportGridData(currentGridInstance, currentGridConfig);
2356
+ } else {
2357
+ console.error('Grid instance or configuration not available for export');
2358
+ }
2359
+ };
2360
+
2361
+ if (isNewButton) {
2362
+ // Append the export button to the grid container
2363
+ gridContainer.parentNode.insertBefore(exportButton, gridContainer);
2364
+ exportButton.style.marginBottom = '10px';
2365
+ }
2330
2366
  }
2331
2367
  // Export AG Grid data to PDF
2332
- exportGridDataToPDF = async () => {
2333
- if (!gridInstance || gridInstance.isDestroyed()) {
2368
+ exportGridDataToPDF = async (currentGridInstance, currentGridConfig) => {
2369
+ if (!currentGridInstance || currentGridInstance.isDestroyed()) {
2334
2370
  console.error('Grid API is destroyed or not initialized.');
2335
2371
  return;
2336
2372
  }
@@ -2355,9 +2391,9 @@ dmx.Component('ag-grid', {
2355
2391
  return fieldsAndColIds;
2356
2392
  };
2357
2393
  // Traverse columnDefs to gather fields and colIds
2358
- fieldsAndColIds = traverseColumns(gridConfig.columnDefs);
2394
+ fieldsAndColIds = traverseColumns(currentGridConfig.columnDefs);
2359
2395
  } else {
2360
- fieldsAndColIds = gridConfig.columnDefs.map((column) => ({
2396
+ fieldsAndColIds = currentGridConfig.columnDefs.map((column) => ({
2361
2397
  field: column.field,
2362
2398
  colId: column.colId,
2363
2399
  hide: column.hide,
@@ -2409,19 +2445,19 @@ dmx.Component('ag-grid', {
2409
2445
  return options.wrap_text ? { whiteSpace: 'normal' } : null;
2410
2446
  };
2411
2447
 
2412
- const getColumnData = (gridInstance, isHeader) =>
2413
- gridInstance.getAllDisplayedColumns()
2448
+ const getColumnData = (gInstance, isHeader) =>
2449
+ gInstance.getAllDisplayedColumns()
2414
2450
  .filter(column => fieldsToExport.includes(column.getColDef().field))
2415
2451
  .map(column => {
2416
2452
  const colDef = column.getColDef();
2417
2453
  const field = colDef.field;
2418
2454
  const params = {
2419
- value: isHeader ? null : gridInstance.getValue(column, gridInstance.getDisplayedRowAtIndex(0)),
2420
- data: isHeader ? null : gridInstance.getDisplayedRowAtIndex(0).data,
2421
- node: isHeader ? null : gridInstance.getDisplayedRowAtIndex(0),
2455
+ value: isHeader ? null : gInstance.getValue(column, gInstance.getDisplayedRowAtIndex(0)),
2456
+ data: isHeader ? null : gInstance.getDisplayedRowAtIndex(0).data,
2457
+ node: isHeader ? null : gInstance.getDisplayedRowAtIndex(0),
2422
2458
  colDef,
2423
2459
  column,
2424
- api: gridInstance,
2460
+ api: gInstance,
2425
2461
  context: params.context,
2426
2462
  };
2427
2463
  const cellStyle = applyCellStyle(params);
@@ -2431,39 +2467,55 @@ dmx.Component('ag-grid', {
2431
2467
  cnames[field].custom_name :
2432
2468
  humanize(field)
2433
2469
  ) : '';
2470
+ let cellValue = !isHeader ? (
2471
+ (colDef.cellRenderer && typeof colDef.cellRenderer === 'function') ? colDef.cellRenderer(params) :
2472
+ (colDef.valueFormatter && typeof colDef.valueFormatter === 'function') ? colDef.valueFormatter(params) :
2473
+ gInstance.getValue(column, gInstance.getDisplayedRowAtIndex(0)) ?? ''
2474
+ ) : headerName;
2475
+
2476
+ // Remove HTML tags if export_remove_html is true
2477
+ if (options.export_remove_html && typeof cellValue === 'string') {
2478
+ cellValue = removeHtmlTags(cellValue);
2479
+ }
2480
+
2434
2481
  return {
2435
- text: !isHeader ? (
2436
- (colDef.cellRenderer && typeof colDef.cellRenderer === 'function') ? colDef.cellRenderer(params) :
2437
- (colDef.valueFormatter && typeof colDef.valueFormatter === 'function') ? colDef.valueFormatter(params) :
2438
- gridInstance.getValue(column, gridInstance.getDisplayedRowAtIndex(0)) ?? ''
2439
- ) : headerName,
2482
+ text: cellValue,
2440
2483
  color: cellStyle?.color ?? 'black',
2441
2484
  fillColor: cellStyle?.backgroundColor ? cellStyle.backgroundColor.replace('#', '') : undefined,
2442
2485
  };
2443
- });
2486
+ });;
2444
2487
 
2445
- const columns = gridInstance.getColumnState();
2488
+ const columns = currentGridInstance.getColumnState();
2446
2489
  const columnMap = new Map(columns.map(col => [col.colId, col]));
2447
2490
 
2448
2491
  const rows = [];
2449
- gridInstance.forEachNode(node => {
2492
+ currentGridInstance.forEachNode(node => {
2450
2493
  const row = fieldsToExport.map(field => {
2451
2494
  const col = columnMap.get(field);
2452
- const colDef = col ? gridInstance.getColumnDefs().find(def => def.colId === col.colId) : {};
2495
+ const colDef = col ? currentGridInstance.getColumnDefs().find(def => def.colId === col.colId) : {};
2453
2496
  const params = {
2454
- value: gridInstance.getCellValue({ rowNode: node, colKey: col.colId }) ?? '-',
2497
+ value: currentGridInstance.getCellValue({ rowNode: node, colKey: col.colId }) ?? '-',
2455
2498
  data: node.data,
2456
2499
  node,
2457
2500
  colDef,
2458
- column: gridInstance.getColumnState().find(col => col.colId === col.colId),
2459
- api: gridInstance,
2501
+ column: currentGridInstance.getColumnState().find(col => col.colId === col.colId),
2502
+ api: currentGridInstance,
2460
2503
  };
2461
2504
  const cellStyle = applyCellStyle(params);
2462
- const value = gridInstance.getCellValue({ rowNode: node, colKey: col.colId }) ?? '-';
2505
+ let value = currentGridInstance.getCellValue({ rowNode: node, colKey: col.colId }) ?? '-';
2506
+
2507
+ // Get the rendered value
2508
+ let displayValue = (colDef.cellRenderer && typeof colDef.cellRenderer === 'function') ? colDef.cellRenderer(params) :
2509
+ (colDef.valueFormatter && typeof colDef.valueFormatter === 'function') ? colDef.valueFormatter(params) :
2510
+ value;
2511
+
2512
+ // Remove HTML tags if export_remove_html is true
2513
+ if (options.export_remove_html && typeof displayValue === 'string') {
2514
+ displayValue = removeHtmlTags(displayValue);
2515
+ }
2516
+
2463
2517
  return {
2464
- text: (colDef.cellRenderer && typeof colDef.cellRenderer === 'function') ? colDef.cellRenderer(params) :
2465
- (colDef.valueFormatter && typeof colDef.valueFormatter === 'function') ? colDef.valueFormatter(params) :
2466
- value,
2518
+ text: displayValue,
2467
2519
  color: cellStyle?.color ?? 'black',
2468
2520
  fillColor: cellStyle?.backgroundColor ? cellStyle.backgroundColor.replace('#', '') : undefined,
2469
2521
  };
@@ -2476,7 +2528,7 @@ dmx.Component('ag-grid', {
2476
2528
  table: {
2477
2529
  headerRows: 1,
2478
2530
  widths: fieldsToExport.map(() => `${100 / fieldsToExport.length}%`),
2479
- body: [getColumnData(gridInstance, true), ...rows],
2531
+ body: [getColumnData(currentGridInstance, true), ...rows],
2480
2532
  heights: (rowIndex) => (rowIndex === 0 ? 40 : 15),
2481
2533
  fillColor: (rowIndex, colIndex) => rows[rowIndex][colIndex].fillColor,
2482
2534
  color: (rowIndex, colIndex) => rows[rowIndex][colIndex].color,
@@ -2486,39 +2538,49 @@ dmx.Component('ag-grid', {
2486
2538
  pdfMake.createPdf(documentDefinition).download(options.export_pdf_filename);
2487
2539
  };
2488
2540
  if (exportToPDF) {
2489
- const existingPdfExportButton = document.getElementById('exportPdfButton');
2490
- if (existingPdfExportButton) {
2491
- return;
2492
- }
2493
- const exportPdfButton = document.createElement('button');
2494
- exportPdfButton.id = 'exportPdfButton';
2495
- const icon = document.createElement('i');
2496
- icon.classList.add('fas', 'fa-file-pdf');
2497
- exportPdfButton.appendChild(icon);
2541
+ let exportPdfButton = document.getElementById(`exportPdfButton-${options.id}`);
2542
+ let isNewPdfButton = false;
2543
+ if (!exportPdfButton) {
2544
+ isNewPdfButton = true;
2545
+ exportPdfButton = document.createElement('button');
2546
+ exportPdfButton.id = `exportPdfButton-${options.id}`;
2547
+ const icon = document.createElement('i');
2548
+ icon.classList.add('fas', 'fa-file-pdf');
2549
+ exportPdfButton.appendChild(icon);
2498
2550
 
2499
- // Add the button text
2500
- const buttonText = document.createElement('span');
2501
- buttonText.innerText = ' Export to PDF';
2502
- exportPdfButton.appendChild(buttonText);
2503
- exportPdfButton.style.backgroundColor = '#4CAF50';
2504
- exportPdfButton.style.border = 'none';
2505
- exportPdfButton.style.color = 'white';
2506
- exportPdfButton.style.padding = '5px 10px';
2507
- exportPdfButton.style.textAlign = 'center';
2508
- exportPdfButton.style.textDecoration = 'none';
2509
- exportPdfButton.style.display = 'inline-block';
2510
- exportPdfButton.style.fontSize = '14px';
2511
- exportPdfButton.style.borderRadius = '5px';
2512
- exportPdfButton.style.cursor = 'pointer';
2513
- exportPdfButton.style.marginBottom = '10px';
2514
-
2515
- exportPdfButton.addEventListener('click', () => {
2516
- exportGridDataToPDF(this)
2517
- })
2551
+ // Add the button text
2552
+ const buttonText = document.createElement('span');
2553
+ buttonText.innerText = ' Export to PDF';
2554
+ exportPdfButton.appendChild(buttonText);
2555
+ exportPdfButton.style.backgroundColor = '#4CAF50';
2556
+ exportPdfButton.style.border = 'none';
2557
+ exportPdfButton.style.color = 'white';
2558
+ exportPdfButton.style.padding = '5px 10px';
2559
+ exportPdfButton.style.textAlign = 'center';
2560
+ exportPdfButton.style.textDecoration = 'none';
2561
+ exportPdfButton.style.display = 'inline-block';
2562
+ exportPdfButton.style.fontSize = '14px';
2563
+ exportPdfButton.style.borderRadius = '5px';
2564
+ exportPdfButton.style.cursor = 'pointer';
2565
+ exportPdfButton.style.marginBottom = '10px';
2566
+ }
2567
+
2568
+ // Always update the click handler to ensure it has the latest gridInstance and gridConfig
2569
+ exportPdfButton.onclick = () => {
2570
+ const currentGridInstance = this.get('gridInstance');
2571
+ const currentGridConfig = this.gridConfig;
2572
+ if (currentGridInstance && currentGridConfig) {
2573
+ exportGridDataToPDF(currentGridInstance, currentGridConfig);
2574
+ } else {
2575
+ console.error('Grid instance or configuration not available for export');
2576
+ }
2577
+ };
2518
2578
 
2519
- // Append the export button to the grid container
2520
- gridContainer.parentNode.insertBefore(exportPdfButton, gridContainer);
2521
- exportPdfButton.style.marginBottom = '10px';
2579
+ if (isNewPdfButton) {
2580
+ // Append the export button to the grid container
2581
+ gridContainer.parentNode.insertBefore(exportPdfButton, gridContainer);
2582
+ exportPdfButton.style.marginBottom = '10px';
2583
+ }
2522
2584
  }
2523
2585
  const paginationPanelCss = `
2524
2586
  /* 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.13",
3
+ "version": "2.0.15",
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",