@wavemaker/app-ng-runtime 11.14.1-1.6289 → 11.14.1-10.6348

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 (67) hide show
  1. package/components/base/bundles/index.umd.js +86 -17
  2. package/components/base/esm2022/pipes/custom-pipes.mjs +10 -10
  3. package/components/base/esm2022/utils/widget-utils.mjs +3 -3
  4. package/components/base/esm2022/widgets/common/base/base.component.mjs +67 -7
  5. package/components/base/esm2022/widgets/common/lazy-load/lazy-load.directive.mjs +7 -3
  6. package/components/base/esm2022/widgets/framework/property-change-handler.mjs +7 -2
  7. package/components/base/fesm2022/index.mjs +87 -18
  8. package/components/base/fesm2022/index.mjs.map +1 -1
  9. package/components/base/pipes/custom-pipes.d.ts +5 -5
  10. package/components/basic/label/bundles/index.umd.js +9 -1
  11. package/components/basic/label/esm2022/label.directive.mjs +10 -2
  12. package/components/basic/label/fesm2022/index.mjs +9 -1
  13. package/components/basic/label/fesm2022/index.mjs.map +1 -1
  14. package/components/data/pagination/bundles/index.umd.js +4 -0
  15. package/components/data/pagination/esm2022/pagination.component.mjs +5 -1
  16. package/components/data/pagination/fesm2022/index.mjs +4 -0
  17. package/components/data/pagination/fesm2022/index.mjs.map +1 -1
  18. package/components/data/table/bundles/index.umd.js +371 -15
  19. package/components/data/table/esm2022/table-action/table-action.directive.mjs +8 -1
  20. package/components/data/table/esm2022/table-column/table-column.directive.mjs +107 -3
  21. package/components/data/table/esm2022/table-column-group/table-column-group.directive.mjs +9 -1
  22. package/components/data/table/esm2022/table-cud.directive.mjs +8 -2
  23. package/components/data/table/esm2022/table-filter.directive.mjs +12 -2
  24. package/components/data/table/esm2022/table-row/table-row.directive.mjs +8 -1
  25. package/components/data/table/esm2022/table-row-action/table-row-action.directive.mjs +8 -1
  26. package/components/data/table/esm2022/table.component.mjs +219 -12
  27. package/components/data/table/fesm2022/index.mjs +371 -15
  28. package/components/data/table/fesm2022/index.mjs.map +1 -1
  29. package/components/data/table/table-action/table-action.directive.d.ts +3 -2
  30. package/components/data/table/table-column/table-column.directive.d.ts +3 -2
  31. package/components/data/table/table-column-group/table-column-group.directive.d.ts +3 -2
  32. package/components/data/table/table-cud.directive.d.ts +3 -1
  33. package/components/data/table/table-filter.directive.d.ts +3 -1
  34. package/components/data/table/table-row/table-row.directive.d.ts +3 -2
  35. package/components/data/table/table-row-action/table-row-action.directive.d.ts +3 -2
  36. package/components/data/table/table.component.d.ts +6 -2
  37. package/components/navigation/menu/bundles/index.umd.js +5 -0
  38. package/components/navigation/menu/esm2022/menu.component.mjs +6 -1
  39. package/components/navigation/menu/fesm2022/index.mjs +5 -0
  40. package/components/navigation/menu/fesm2022/index.mjs.map +1 -1
  41. package/components/navigation/popover/bundles/index.umd.js +6 -6
  42. package/components/navigation/popover/esm2022/popover.component.mjs +4 -4
  43. package/components/navigation/popover/fesm2022/index.mjs +3 -3
  44. package/components/navigation/popover/fesm2022/index.mjs.map +1 -1
  45. package/components/navigation/popover/popover.component.d.ts +6 -0
  46. package/core/bundles/index.umd.js +411 -82
  47. package/core/esm2022/public_api.mjs +3 -3
  48. package/core/esm2022/utils/utils.mjs +6 -2
  49. package/core/esm2022/utils/watcher.mjs +402 -81
  50. package/core/fesm2022/index.mjs +410 -84
  51. package/core/fesm2022/index.mjs.map +1 -1
  52. package/core/public_api.d.ts +2 -2
  53. package/core/utils/utils.d.ts +1 -0
  54. package/core/utils/watcher.d.ts +28 -5
  55. package/npm-shrinkwrap.json +2 -2
  56. package/package-lock.json +2 -2
  57. package/package.json +1 -1
  58. package/runtime/base/bundles/index.umd.js +22 -2
  59. package/runtime/base/esm2022/components/app-component/app.component.mjs +4 -2
  60. package/runtime/base/esm2022/components/base-page.component.mjs +6 -2
  61. package/runtime/base/esm2022/components/base-partial.component.mjs +7 -2
  62. package/runtime/base/esm2022/components/base-prefab.component.mjs +7 -2
  63. package/runtime/base/esm2022/components/base-spa-page.component.mjs +6 -2
  64. package/runtime/base/esm2022/services/pipe-provider.service.mjs +4 -4
  65. package/runtime/base/fesm2022/index.mjs +23 -3
  66. package/runtime/base/fesm2022/index.mjs.map +1 -1
  67. package/scripts/datatable/datatable.js +101 -15
@@ -176,8 +176,15 @@ class TableComponent extends StylableComponent {
176
176
  this.setDataGridOption('colDefs', getClonedObject(this.fieldDefs));
177
177
  }
178
178
  // If data and colDefs are present, call on before data render event
179
+ // Note: Errors in beforedatarender should not prevent table rendering
179
180
  if (!this.isdynamictable && !isEmpty(newValue) && gridOptions.colDefs.length) {
180
- this.invokeEventCallback('beforedatarender', { $data: this._gridData, $columns: this.columns, data: this._gridData, columns: this.columns });
181
+ try {
182
+ this.invokeEventCallback('beforedatarender', { $data: this._gridData, $columns: this.columns, data: this._gridData, columns: this.columns });
183
+ }
184
+ catch (error) {
185
+ // Log error but continue with rendering - beforedatarender errors should not block table rendering
186
+ console.warn('Error in beforedatarender event callback, continuing with table rendering:', error);
187
+ }
181
188
  }
182
189
  this.setDataGridOption('data', getClonedObject(this._gridData));
183
190
  }
@@ -570,7 +577,7 @@ class TableComponent extends StylableComponent {
570
577
  this.prevData = getClonedObject(row);
571
578
  },
572
579
  afterRowUpdate: (row, e, callBack, options) => {
573
- this.updateRecord(extend({}, options, { row, 'prevData': this.prevData, 'event': e, 'callBack': callBack }));
580
+ this.updateRecord(extend({}, options, { row, 'prevData': options.rowindex ? options.rowindex : this.prevData, 'event': e, 'callBack': callBack }));
574
581
  },
575
582
  onBeforeRowUpdate: (row, e, options) => {
576
583
  return this.invokeEventCallback('beforerowupdate', { $event: e, $data: row, row, options: options });
@@ -1224,6 +1231,10 @@ class TableComponent extends StylableComponent {
1224
1231
  return this.actualPageSize || 5;
1225
1232
  }
1226
1233
  watchVariableDataSet(newVal) {
1234
+ // Guard against component destruction
1235
+ if (this.isDestroyed) {
1236
+ return;
1237
+ }
1227
1238
  let result;
1228
1239
  // Check for Variable filters if applied
1229
1240
  if (this.gridOptions.isNavTypeScrollOrOndemand()) {
@@ -1281,6 +1292,12 @@ class TableComponent extends StylableComponent {
1281
1292
  }
1282
1293
  /*Return if data is invalid.*/
1283
1294
  if (!this.isDataValid()) {
1295
+ // If data is invalid and variableInflight is still true, clear loading state
1296
+ // This prevents tables from getting stuck in loading when data is invalid
1297
+ if (this.variableInflight) {
1298
+ this.variableInflight = false;
1299
+ this.setGridData([]);
1300
+ }
1284
1301
  return;
1285
1302
  }
1286
1303
  // If value is empty or in studio mode, dont enable the navigation
@@ -1308,7 +1325,13 @@ class TableComponent extends StylableComponent {
1308
1325
  // @ts-ignore
1309
1326
  if (!isObject(newVal) || newVal === '' || (newVal && newVal.dataValue === '')) {
1310
1327
  if (!this.variableInflight) {
1311
- // If variable has finished loading and resultSet is empty, ender empty data
1328
+ // If variable has finished loading and resultSet is empty, render empty data
1329
+ this.setGridData([]);
1330
+ }
1331
+ else {
1332
+ // If variableInflight is still true but we have invalid/empty data, clear loading state
1333
+ // This handles cases where data never arrives or is invalid
1334
+ this.variableInflight = false;
1312
1335
  this.setGridData([]);
1313
1336
  }
1314
1337
  return;
@@ -1318,13 +1341,143 @@ class TableComponent extends StylableComponent {
1318
1341
  }
1319
1342
  }
1320
1343
  ngOnDestroy() {
1344
+ // MEMORY LEAK FIX: Remove document click listener
1321
1345
  document.removeEventListener('click', this.documentClickBind);
1346
+ // MEMORY LEAK FIX: Unsubscribe from navigator watches
1322
1347
  if (this.navigatorResultWatch) {
1323
1348
  this.navigatorResultWatch.unsubscribe();
1349
+ this.navigatorResultWatch = null;
1324
1350
  }
1325
1351
  if (this.navigatorMaxResultWatch) {
1326
1352
  this.navigatorMaxResultWatch.unsubscribe();
1353
+ this.navigatorMaxResultWatch = null;
1354
+ }
1355
+ // MEMORY LEAK FIX: Clear all ViewContainerRef embedded views
1356
+ // These hold references to row data, custom expressions, and inline widgets
1357
+ if (this.customExprViewRef) {
1358
+ this.customExprViewRef.clear();
1359
+ }
1360
+ if (this.rowActionsViewRef) {
1361
+ this.rowActionsViewRef.clear();
1362
+ }
1363
+ if (this.filterViewRef) {
1364
+ this.filterViewRef.clear();
1365
+ }
1366
+ if (this.inlineEditViewRef) {
1367
+ this.inlineEditViewRef.clear();
1368
+ }
1369
+ if (this.inlineEditNewViewRef) {
1370
+ this.inlineEditNewViewRef.clear();
1371
+ }
1372
+ if (this.rowDetailViewRef) {
1373
+ this.rowDetailViewRef.clear();
1374
+ }
1375
+ if (this.rowExpansionActionViewRef) {
1376
+ this.rowExpansionActionViewRef.clear();
1377
+ }
1378
+ if (this.dynamicTableRef) {
1379
+ this.dynamicTableRef.clear();
1380
+ }
1381
+ // MEMORY LEAK FIX: Clear compiled template caches
1382
+ this.rowActionsCompiledTl = {};
1383
+ this.rowFilterCompliedTl = {};
1384
+ this.inlineCompliedTl = {};
1385
+ this.inlineNewCompliedTl = {};
1386
+ this.customExprCompiledTl = {};
1387
+ this.customExprCompiledSummaryTl = {};
1388
+ this.rowDefInstances = {};
1389
+ this.rowDefMap = {};
1390
+ this.rowExpansionActionTl = {};
1391
+ // MEMORY LEAK FIX: Clear dynamic context
1392
+ if (this._dynamicContext) {
1393
+ Object.keys(this._dynamicContext).forEach(key => {
1394
+ delete this._dynamicContext[key];
1395
+ });
1396
+ this._dynamicContext = null;
1397
+ }
1398
+ // MEMORY LEAK FIX: Clear data arrays
1399
+ this._gridData = [];
1400
+ this.items = [];
1401
+ this.selectedItems = [];
1402
+ this.fieldDefs = [];
1403
+ this.fullFieldDefs = [];
1404
+ this.gridData = [];
1405
+ this.__fullData = null;
1406
+ // MEMORY LEAK FIX: Destroy jQuery datatable widget before clearing gridOptions
1407
+ if (this.datagridElement && this.datagridElement.datatable) {
1408
+ try {
1409
+ this.datagridElement.datatable('destroy');
1410
+ }
1411
+ catch (e) {
1412
+ // Ignore errors during destroy
1413
+ }
1414
+ }
1415
+ // MEMORY LEAK FIX: Clear gridOptions to release all function closures and data
1416
+ // gridOptions holds many closures that capture 'this' and prevent GC
1417
+ if (this.gridOptions) {
1418
+ // Clear data array
1419
+ if (this.gridOptions.data) {
1420
+ this.gridOptions.data = [];
1421
+ }
1422
+ // Clear column definitions
1423
+ if (this.gridOptions.colDefs) {
1424
+ this.gridOptions.colDefs = [];
1425
+ }
1426
+ // Clear row actions
1427
+ if (this.gridOptions.rowActions) {
1428
+ this.gridOptions.rowActions = [];
1429
+ }
1430
+ // Clear header config
1431
+ if (this.gridOptions.headerConfig) {
1432
+ this.gridOptions.headerConfig = [];
1433
+ }
1434
+ // Nullify all function references to break closures
1435
+ Object.keys(this.gridOptions).forEach(key => {
1436
+ if (typeof this.gridOptions[key] === 'function') {
1437
+ this.gridOptions[key] = null;
1438
+ }
1439
+ });
1327
1440
  }
1441
+ // MEMORY LEAK FIX: Clear other data structures
1442
+ this.columns = {};
1443
+ this.formfields = {};
1444
+ this.rowFilter = {};
1445
+ this.actions = [];
1446
+ this._actions = { header: [], footer: [] };
1447
+ this.exportOptions = [];
1448
+ this.headerConfig = [];
1449
+ this.rowActions = [];
1450
+ // MEMORY LEAK FIX: Clear all @ContentChildren QueryLists holding template references
1451
+ // These QueryLists hold TemplateRef instances that create circular references to the parent LView
1452
+ if (this.rowActionTmpl) {
1453
+ this.rowActionTmpl.reset([]);
1454
+ }
1455
+ if (this.filterTmpl) {
1456
+ this.filterTmpl.reset([]);
1457
+ }
1458
+ if (this.inlineWidgetTmpl) {
1459
+ this.inlineWidgetTmpl.reset([]);
1460
+ }
1461
+ if (this.inlineWidgetNewTmpl) {
1462
+ this.inlineWidgetNewTmpl.reset([]);
1463
+ }
1464
+ if (this.customExprTmpl) {
1465
+ this.customExprTmpl.reset([]);
1466
+ }
1467
+ if (this.rowExpansionActionTmpl) {
1468
+ this.rowExpansionActionTmpl.reset([]);
1469
+ }
1470
+ // MEMORY LEAK FIX: Clear @ContentChild template reference
1471
+ this.rowExpansionTmpl = null;
1472
+ // MEMORY LEAK FIX: Complete and clear subjects
1473
+ if (this.selectedItemChange) {
1474
+ this.selectedItemChange.complete();
1475
+ this.selectedItemChange = null;
1476
+ }
1477
+ // MEMORY LEAK FIX: Clear ViewChild references
1478
+ this.dataNavigator = null;
1479
+ this._tableElement = null;
1480
+ // console.log("table component destroyed");
1328
1481
  super.ngOnDestroy();
1329
1482
  }
1330
1483
  addRowIndex(row) {
@@ -1395,6 +1548,9 @@ class TableComponent extends StylableComponent {
1395
1548
  if (!key.endsWith('_filter') && ((key.endsWith('_new') && newRow) || (!key.endsWith('_new') && !newRow))) {
1396
1549
  ctrls[key].setValue('');
1397
1550
  this.resetFormControl(ctrls[key]);
1551
+ // MEMORY LEAK FIX: Clear validators to release references
1552
+ ctrls[key].clearValidators();
1553
+ ctrls[key].clearAsyncValidators();
1398
1554
  }
1399
1555
  });
1400
1556
  }
@@ -1714,7 +1870,14 @@ class TableComponent extends StylableComponent {
1714
1870
  defaultFieldDefs.forEach(col => {
1715
1871
  this.columns[col.field] = col;
1716
1872
  });
1717
- this.invokeEventCallback('beforedatarender', { $data: data, $columns: this.columns, data: data, columns: this.columns });
1873
+ // Note: Errors in beforedatarender should not prevent table rendering
1874
+ try {
1875
+ this.invokeEventCallback('beforedatarender', { $data: data, $columns: this.columns, data: data, columns: this.columns });
1876
+ }
1877
+ catch (error) {
1878
+ // Log error but continue with rendering - beforedatarender errors should not block table rendering
1879
+ console.warn('Error in beforedatarender event callback, continuing with table rendering:', error);
1880
+ }
1718
1881
  defaultFieldDefs = [];
1719
1882
  // Apply the changes made by the user
1720
1883
  forEach(this.columns, val => {
@@ -1753,23 +1916,30 @@ class TableComponent extends StylableComponent {
1753
1916
  return sortExp || '';
1754
1917
  }
1755
1918
  onPropertyChange(key, nv, ov) {
1919
+ // Guard against property changes after component destruction
1920
+ if (this.isDestroyed) {
1921
+ return;
1922
+ }
1756
1923
  let enableNewRow, widgetState;
1757
1924
  switch (key) {
1758
1925
  case 'datasource':
1759
1926
  // Fix for [WMS-23653] when startUpdate is false (request on page load property is unchecked),
1760
1927
  // then set status msg as "No data found"
1761
- if (this.allowpagesizechange) {
1928
+ if (this.allowpagesizechange && this.datasource) {
1762
1929
  this.datasource.maxResults = this.pagesize || this.datasource.maxResults;
1763
1930
  }
1764
- if (nv.startUpdate === false) {
1931
+ if (nv && nv.startUpdate === false) {
1765
1932
  this.variableInflight = false;
1766
1933
  this.callDataGridMethod('setStatus', 'nodata', this.nodatamessage);
1767
1934
  }
1768
- if (get(this.datasource, 'category') !== 'wm.Variable') {
1935
+ if (this.datasource && get(this.datasource, 'category') !== 'wm.Variable') {
1769
1936
  this.headerselectall = false;
1770
1937
  this.setDataGridOption("headerselectall", false);
1771
1938
  }
1772
- this.watchVariableDataSet(this.dataset);
1939
+ // Process dataset when datasource is set, especially if dataset was previously skipped
1940
+ if (this.datasource && this.dataset !== undefined) {
1941
+ this.watchVariableDataSet(this.dataset);
1942
+ }
1773
1943
  this.onDataSourceChange();
1774
1944
  break;
1775
1945
  case 'dataset':
@@ -1777,6 +1947,12 @@ class TableComponent extends StylableComponent {
1777
1947
  this.gridOptions.setIsNextPageData(false);
1778
1948
  }
1779
1949
  if (this.binddatasource && !this.datasource) {
1950
+ // If datasource is not set yet, clear loading state and show no data
1951
+ // This prevents tables from being stuck in loading state
1952
+ if (this.variableInflight) {
1953
+ this.variableInflight = false;
1954
+ this.callDataGridMethod('setStatus', 'nodata', this.nodatamessage);
1955
+ }
1780
1956
  return;
1781
1957
  }
1782
1958
  // if table is inside list then table dataset will be set as "item.XXX" and there is no datasource.
@@ -1880,9 +2056,11 @@ class TableComponent extends StylableComponent {
1880
2056
  this.allowpagesizechange = nv;
1881
2057
  break;
1882
2058
  case 'pagesizeoptions':
1883
- this.gridOptions.pagesizeoptions = nv;
1884
- this.pagesizeoptions = nv;
1885
- this.setDefaultPageSize(nv);
2059
+ this.prevPagesizeoptions = this.sanitizeCommaSeparatedIntegers(ov);
2060
+ this.gridOptions.pagesizeoptions = this.sanitizeCommaSeparatedIntegers(nv);
2061
+ this.pagesizeoptions = this.sanitizeCommaSeparatedIntegers(nv);
2062
+ if (this.allowpagesizechange)
2063
+ this.setDefaultPageSize(nv);
1886
2064
  break;
1887
2065
  case 'multiselecttitle':
1888
2066
  this.setDataGridOption('multiselecttitle', nv);
@@ -1926,12 +2104,41 @@ class TableComponent extends StylableComponent {
1926
2104
  this.pagesize = nv;
1927
2105
  }
1928
2106
  this.updatedPageSize = nv;
2107
+ if (this.isPageSizeOptionsChanged()) {
2108
+ this.dataNavigator.defaultPageSizeOptions = this.pagesizeoptions?.split(',').map(Number).sort((a, b) => a - b) || [];
2109
+ this.dataNavigator.pageSizeOptions = [...this.dataNavigator.defaultPageSizeOptions];
2110
+ }
1929
2111
  }
1930
2112
  this.dataNavigator.options = {
1931
2113
  maxResults: nv
1932
2114
  };
1933
2115
  this.dataNavigator.widget.maxResults = nv;
1934
2116
  this.dataNavigator.maxResults = nv;
2117
+ if (this.datasource) {
2118
+ this.datasource.maxResults = this.pagesize || this.datasource.maxResults;
2119
+ }
2120
+ }
2121
+ isPageSizeOptionsChanged() {
2122
+ return !isEqual(this.prevPagesizeoptions, this.pagesizeoptions);
2123
+ }
2124
+ selectPageSize(pagesize) {
2125
+ if (!this.allowpagesizechange && !pagesize)
2126
+ return;
2127
+ if (pagesize < this.dataNavigator.pageSizeOptions[0] || pagesize > this.dataNavigator.pageSizeOptions[this.dataNavigator.pageSizeOptions.length - 1]
2128
+ || !this.dataNavigator.pageSizeOptions.includes(Number(pagesize))) {
2129
+ pagesize = this.dataNavigator.pageSizeOptions[0];
2130
+ }
2131
+ this.dataNavigator.onPageSizeChange(undefined, pagesize);
2132
+ }
2133
+ sanitizeCommaSeparatedIntegers(input) {
2134
+ if (!input)
2135
+ return "";
2136
+ const uniqueNumbers = Array.from(new Set(input
2137
+ .split(",")
2138
+ .map(v => v.trim())
2139
+ .filter(v => /^-?\d+$/.test(v))
2140
+ .map(v => Math.abs(parseInt(v, 10)))));
2141
+ return uniqueNumbers.join(",");
1935
2142
  }
1936
2143
  onDataSourceChange() {
1937
2144
  this.fieldDefs.forEach(col => {
@@ -2457,7 +2664,7 @@ class TableCUDDirective {
2457
2664
  this.updateVariable(response, options.callBack);
2458
2665
  }
2459
2666
  else if (!this.table.datasource.execute(DataSource.Operation.IS_API_AWARE)) {
2460
- this.table.initiateSelectItem('current', response, undefined, false, options.callBack);
2667
+ this.table.initiateSelectItem('current', response, undefined, this.table.datasource.category === 'wm.Variable', options.callBack);
2461
2668
  }
2462
2669
  triggerFn(options.success, response);
2463
2670
  this.table.invokeEventCallback('rowupdate', { $event: options.event, $data: response, row: response });
@@ -2707,6 +2914,12 @@ class TableCUDDirective {
2707
2914
  this.table.callDataGridMethod('cancelEdit', $row);
2708
2915
  }
2709
2916
  }
2917
+ ngOnDestroy() {
2918
+ // MEMORY LEAK FIX: Clear all references
2919
+ this.table = null;
2920
+ this.dialogService = null;
2921
+ this.app = null;
2922
+ }
2710
2923
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TableCUDDirective, deps: [{ token: TableComponent, self: true }, { token: i2.AbstractDialogService }, { token: i2.App }], target: i0.ɵɵFactoryTarget.Directive }); }
2711
2924
  static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.2.13", type: TableCUDDirective, isStandalone: true, selector: "[wmTableCUD]", ngImport: i0 }); }
2712
2925
  }
@@ -3019,6 +3232,12 @@ class TableFilterSortDirective {
3019
3232
  // Function that checks if a given string is a valid date and returns the timestamp if it is, or NaN if it's not.
3020
3233
  parseDateString(dateString) {
3021
3234
  const timestamp = Date.parse(dateString);
3235
+ // handling case when string starts with string and end with number
3236
+ const trimmed = dateString.trim();
3237
+ const monthRegex = /\b(?:Jan(?:uary)?|Feb(?:ruary)?|Mar(?:ch)?|Apr(?:il)?|May|Jun(?:e)?|Jul(?:y)?|Aug(?:ust)?|Sep(?:t(?:ember)?)?|Oct(?:ober)?|Nov(?:ember)?|Dec(?:ember)?)\b/i;
3238
+ if (/^[A-Za-z]+/.test(trimmed) && /\d+$/.test(trimmed) && !monthRegex.test(trimmed)) {
3239
+ return NaN;
3240
+ }
3022
3241
  if (!isNaN(timestamp)) {
3023
3242
  return timestamp;
3024
3243
  }
@@ -3034,7 +3253,7 @@ class TableFilterSortDirective {
3034
3253
  const fieldValue = get(find(data, sortObj.field), sortObj.field);
3035
3254
  const isValidDateString = typeof fieldValue === 'string' ? this.parseDateString(fieldValue) : NaN;
3036
3255
  if (!isNaN(isValidDateString)) { // if the field is a date string
3037
- data = orderBy(data, [(item) => this.parseDateString(item[sortObj.field])], [sortObj.direction]);
3256
+ data = orderBy(data, [(item) => this.parseDateString(get(item, sortObj.field))], [sortObj.direction]);
3038
3257
  }
3039
3258
  else if (sortObj.sortBy ? this.table.columns[sortObj.sortBy]?.caseinsensitive : this.table.columns[sortObj.field]?.caseinsensitive) {
3040
3259
  //Fix for [WMS-27505]: Added case-insensitive sorting so that uppercase and lowercase letters are treated the same when sorting.
@@ -3396,6 +3615,10 @@ class TableFilterSortDirective {
3396
3615
  condition: logicalOp
3397
3616
  });
3398
3617
  }
3618
+ ngOnDestroy() {
3619
+ // MEMORY LEAK FIX: Clear table reference
3620
+ this.table = null;
3621
+ }
3399
3622
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TableFilterSortDirective, deps: [{ token: TableComponent, self: true }], target: i0.ɵɵFactoryTarget.Directive }); }
3400
3623
  static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.2.13", type: TableFilterSortDirective, isStandalone: true, selector: "[wmTableFilterSort]", ngImport: i0 }); }
3401
3624
  }
@@ -3482,6 +3705,13 @@ class TableActionDirective extends BaseComponent {
3482
3705
  this.buttonDef[key] = nv;
3483
3706
  }
3484
3707
  }
3708
+ ngOnDestroy() {
3709
+ // MEMORY LEAK FIX: Clear table and buttonDef references
3710
+ this.table = null;
3711
+ this.buttonDef = null;
3712
+ // Call parent ngOnDestroy (BaseComponent has cleanup)
3713
+ super.ngOnDestroy();
3714
+ }
3485
3715
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TableActionDirective, deps: [{ token: i0.Injector }, { token: TableComponent, optional: true }, { token: 'EXPLICIT_CONTEXT', optional: true }], target: i0.ɵɵFactoryTarget.Directive }); }
3486
3716
  static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.2.13", type: TableActionDirective, isStandalone: true, selector: "[wmTableAction]", providers: [
3487
3717
  provideAsWidgetRef(TableActionDirective)
@@ -3646,6 +3876,14 @@ class TableColumnGroupDirective extends BaseComponent {
3646
3876
  const fieldName = this.group && this.group.name;
3647
3877
  setHeaderConfigForTable(this.table.headerConfig, this.config, fieldName, fieldName ? colIndex : headerIndex);
3648
3878
  }
3879
+ ngOnDestroy() {
3880
+ // MEMORY LEAK FIX: Clear table, group, and config references
3881
+ this.table = null;
3882
+ this.group = null;
3883
+ this.config = null;
3884
+ // Call parent ngOnDestroy (BaseComponent has cleanup)
3885
+ super.ngOnDestroy();
3886
+ }
3649
3887
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TableColumnGroupDirective, deps: [{ token: i0.Injector }, { token: TableColumnGroupDirective, optional: true, skipSelf: true }, { token: TableComponent, optional: true }, { token: 'EXPLICIT_CONTEXT', optional: true }], target: i0.ɵɵFactoryTarget.Directive }); }
3650
3888
  static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.2.13", type: TableColumnGroupDirective, isStandalone: true, selector: "[wmTableColumnGroup]", providers: [
3651
3889
  provideAsWidgetRef(TableColumnGroupDirective)
@@ -3840,6 +4078,10 @@ class TableColumnDirective extends BaseComponent {
3840
4078
  }
3841
4079
  // Remove validators for the inline widget and set form to untouched
3842
4080
  removeValidations() {
4081
+ // Guard against component destruction or table/ngform being null
4082
+ if (this.isDestroyed || !this.table || !this.table.ngform) {
4083
+ return;
4084
+ }
3843
4085
  this.table.ngform.markAsUntouched();
3844
4086
  const control = this.getFormControl();
3845
4087
  if (!control) {
@@ -3851,6 +4093,10 @@ class TableColumnDirective extends BaseComponent {
3851
4093
  }
3852
4094
  // Apply default|sync|async|prop validators for QuickEdit new row form control
3853
4095
  applyNewRowValidations() {
4096
+ // Guard against component destruction or table/ngform being null
4097
+ if (this.isDestroyed || !this.table || !this.table.ngform) {
4098
+ return;
4099
+ }
3854
4100
  if (!this._checkNewEditableRowControl()) {
3855
4101
  return;
3856
4102
  }
@@ -3867,22 +4113,37 @@ class TableColumnDirective extends BaseComponent {
3867
4113
  }
3868
4114
  // Remove validators for the QuickEdit new row widget and set form to untouched
3869
4115
  removeNewRowValidations() {
4116
+ // Guard against component destruction or table/ngform being null
4117
+ if (this.isDestroyed || !this.table || !this.table.ngform) {
4118
+ return;
4119
+ }
3870
4120
  this.table.ngform.markAsUntouched();
3871
4121
  if (!this._checkNewEditableRowControl()) {
3872
4122
  return;
3873
4123
  }
3874
4124
  const control = this.getFormControl('_new');
4125
+ if (!control) {
4126
+ return;
4127
+ }
3875
4128
  control.clearValidators();
3876
4129
  control.clearAsyncValidators();
3877
4130
  control.updateValueAndValidity();
3878
4131
  }
3879
4132
  addFormControl(suffix) {
4133
+ // Guard against component destruction or table/ngform being null
4134
+ if (this.isDestroyed || !this.table || !this.table.ngform) {
4135
+ return;
4136
+ }
3880
4137
  const ctrlName = suffix ? (this.binding + suffix) : this.binding;
3881
4138
  this.table.ngform.addControl(ctrlName, this.table.fb.control(''));
3882
4139
  }
3883
4140
  getFormControl(suffix) {
4141
+ // Guard against component destruction or table/ngform being null
4142
+ if (this.isDestroyed || !this.table || !this.table.ngform) {
4143
+ return null;
4144
+ }
3884
4145
  const ctrlName = suffix ? (this.binding + suffix) : this.binding;
3885
- return this.table.ngform.controls[ctrlName];
4146
+ return this.table.ngform.controls[ctrlName] || null;
3886
4147
  }
3887
4148
  _checkNewEditableRowControl() {
3888
4149
  return this._isNewEditableRow && this.getFormControl('_new');
@@ -3956,12 +4217,16 @@ class TableColumnDirective extends BaseComponent {
3956
4217
  }
3957
4218
  // On field value change, apply cascading filter and set validation message
3958
4219
  onValueChange(val, widget) {
4220
+ // Guard against component destruction or table being null
4221
+ if (this.isDestroyed || !this.table) {
4222
+ return;
4223
+ }
3959
4224
  if (val !== null) {
3960
4225
  applyFilterOnField(this.table.datasource, this.widget, this.table.fieldDefs, val, {
3961
4226
  widget: 'edit-widget-type'
3962
4227
  });
3963
4228
  }
3964
- if (this.table.ngform.touched) {
4229
+ if (this.table.ngform && this.table.ngform.touched) {
3965
4230
  this.activeControlType = widget;
3966
4231
  if (widget === 'inlineInstance') {
3967
4232
  this.notifyChanges();
@@ -4252,6 +4517,83 @@ class TableColumnDirective extends BaseComponent {
4252
4517
  this.table.redraw(true);
4253
4518
  }
4254
4519
  }
4520
+ ngOnDestroy() {
4521
+ // MEMORY LEAK FIX: Clear ContentChildren QueryLists
4522
+ if (this._filterInstances) {
4523
+ try {
4524
+ this._filterInstances.reset([]);
4525
+ }
4526
+ catch (e) {
4527
+ // Silently handle cleanup errors - QueryList might already be destroyed
4528
+ }
4529
+ }
4530
+ if (this._inlineInstances) {
4531
+ try {
4532
+ this._inlineInstances.reset([]);
4533
+ }
4534
+ catch (e) {
4535
+ // Silently handle cleanup errors - QueryList might already be destroyed
4536
+ }
4537
+ }
4538
+ if (this._inlineInstancesNew) {
4539
+ try {
4540
+ this._inlineInstancesNew.reset([]);
4541
+ }
4542
+ catch (e) {
4543
+ // Silently handle cleanup errors - QueryList might already be destroyed
4544
+ }
4545
+ }
4546
+ // MEMORY LEAK FIX: Clear all widget instance references
4547
+ this.filterInstance = null;
4548
+ this.inlineInstance = null;
4549
+ this.inlineInstanceNew = null;
4550
+ // MEMORY LEAK FIX: Clear template references
4551
+ this.customExprTmpl = null;
4552
+ this.inlineWidthTempRef = null;
4553
+ this.filterTemplateRef = null;
4554
+ // MEMORY LEAK FIX: Clear dataset references
4555
+ this._filterDataSet = null;
4556
+ this.dataset = null;
4557
+ this._dataoptions = null;
4558
+ this._datasource = null;
4559
+ // MEMORY LEAK FIX: Clear validation objects
4560
+ if (this.fieldValidations) {
4561
+ try {
4562
+ this.fieldValidations.destroy();
4563
+ }
4564
+ catch (e) {
4565
+ // Silently handle cleanup errors
4566
+ }
4567
+ this.fieldValidations = null;
4568
+ }
4569
+ if (this.fieldValidations_new) {
4570
+ try {
4571
+ this.fieldValidations_new.destroy();
4572
+ }
4573
+ catch (e) {
4574
+ // Silently handle cleanup errors
4575
+ }
4576
+ this.fieldValidations_new = null;
4577
+ }
4578
+ this.syncValidators = [];
4579
+ this.asyncValidators = [];
4580
+ // MEMORY LEAK FIX: Clear filter control reference
4581
+ this.filterControl = null;
4582
+ // MEMORY LEAK FIX: Clear notify fields array
4583
+ if (this.notifyForFields) {
4584
+ this.notifyForFields = [];
4585
+ }
4586
+ // MEMORY LEAK FIX: Clear observe fields array
4587
+ if (this.observeOnFields) {
4588
+ this.observeOnFields = [];
4589
+ }
4590
+ // MEMORY LEAK FIX: Clear table and group references
4591
+ // Note: These are injected dependencies, but clearing helps GC
4592
+ this.table = null;
4593
+ this.group = null;
4594
+ // Call parent ngOnDestroy
4595
+ super.ngOnDestroy();
4596
+ }
4255
4597
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TableColumnDirective, deps: [{ token: i0.Injector }, { token: i2.AppDefaults }, { token: TableComponent, optional: true }, { token: TableColumnGroupDirective, optional: true }, { token: 'filterdataset.bind', attribute: true }, { token: 'dataset.bind', attribute: true }, { token: 'EXPLICIT_CONTEXT', optional: true }], target: i0.ɵɵFactoryTarget.Directive }); }
4256
4598
  static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.2.13", type: TableColumnDirective, isStandalone: true, selector: "[wmTableColumn]", providers: [
4257
4599
  provideAsWidgetRef(TableColumnDirective)
@@ -4346,6 +4688,13 @@ class TableRowDirective extends BaseComponent {
4346
4688
  this.config.content = this.content;
4347
4689
  }
4348
4690
  }
4691
+ ngOnDestroy() {
4692
+ // MEMORY LEAK FIX: Clear table and config references
4693
+ this.table = null;
4694
+ this.config = null;
4695
+ // Call parent ngOnDestroy (BaseComponent has cleanup)
4696
+ super.ngOnDestroy();
4697
+ }
4349
4698
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TableRowDirective, deps: [{ token: i0.Injector }, { token: TableComponent, optional: true, skipSelf: true }, { token: 'EXPLICIT_CONTEXT', optional: true }], target: i0.ɵɵFactoryTarget.Directive }); }
4350
4699
  static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.2.13", type: TableRowDirective, isStandalone: true, selector: "[wmTableRow]", providers: [
4351
4700
  provideAsWidgetRef(TableRowDirective)
@@ -4427,6 +4776,13 @@ class TableRowActionDirective extends BaseComponent {
4427
4776
  this.populateAction();
4428
4777
  this.table.registerRowActions(this.buttonDef);
4429
4778
  }
4779
+ ngOnDestroy() {
4780
+ // MEMORY LEAK FIX: Clear table reference and button definition
4781
+ this.table = null;
4782
+ this.buttonDef = null;
4783
+ // Call parent ngOnDestroy (BaseComponent has cleanup)
4784
+ super.ngOnDestroy();
4785
+ }
4430
4786
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TableRowActionDirective, deps: [{ token: i0.Injector }, { token: TableComponent, optional: true }, { token: Context, self: true }, { token: 'EXPLICIT_CONTEXT', optional: true }], target: i0.ɵɵFactoryTarget.Directive }); }
4431
4787
  static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.2.13", type: TableRowActionDirective, isStandalone: true, selector: "[wmTableRowAction]", providers: [
4432
4788
  provideAsWidgetRef(TableRowActionDirective),