From edf5721007ce0745fc81f3f0261fb7e25340cbc1 Mon Sep 17 00:00:00 2001 From: Ghislain B Date: Fri, 19 May 2023 19:33:10 -0400 Subject: [PATCH] fix(export): fix negative number exports to Excel (#977) - fixes an issue identified in Angular-Slickgrid where the negative numbers were seeing negative numbers turned to positive numbers (ref: https://github.com/ghiscoding/Angular-Slickgrid/issues/1135) - also improve perf of `exportWithFormatterWhenDefined` by analyzing `exportWithFormatter` only once instead of twice --- .../vite-demo-vanilla-bundle/src/examples/example03.ts | 10 +++++++--- packages/common/src/formatters/formatterUtilities.ts | 10 ++++------ packages/excel-export/src/excelUtils.spec.ts | 5 +++++ packages/excel-export/src/excelUtils.ts | 4 ++-- 4 files changed, 18 insertions(+), 11 deletions(-) diff --git a/examples/vite-demo-vanilla-bundle/src/examples/example03.ts b/examples/vite-demo-vanilla-bundle/src/examples/example03.ts index 6bdf3931c..b99df1987 100644 --- a/examples/vite-demo-vanilla-bundle/src/examples/example03.ts +++ b/examples/vite-demo-vanilla-bundle/src/examples/example03.ts @@ -18,6 +18,7 @@ import { SortDirectionNumber, } from '@slickgrid-universal/common'; import { ExcelExportService } from '@slickgrid-universal/excel-export'; +import { TextExportService } from '@slickgrid-universal/text-export'; import { Slicker, SlickVanillaGridBundle } from '@slickgrid-universal/vanilla-bundle'; import { ExampleGridOptions } from './example-grid-options'; @@ -124,6 +125,7 @@ export default class Example3 { // filter: { model: Filters.compoundInput }, // formatter: Formatters.dollar, formatter: Formatters.dollar, + exportWithFormatter: true, groupTotalsFormatter: GroupTotalFormatters.sumTotalsDollar, type: FieldType.number, grouping: { @@ -286,11 +288,12 @@ export default class Example3 { enableAutoSizeColumns: true, enableAutoResize: true, enableCellNavigation: true, + enableTextExport: true, enableExcelExport: true, excelExportOptions: { exportWithFormatter: true }, - registerExternalResources: [this.excelExportService], + registerExternalResources: [new TextExportService(), this.excelExportService], enableFiltering: true, rowSelectionOptions: { // True (Single Selection), False (Multiple Selections) @@ -352,6 +355,7 @@ export default class Example3 { const randomMonth = Math.floor(Math.random() * 11); const randomDay = Math.floor((Math.random() * 29)); const randomFinish = new Date(randomFinishYear, (randomMonth + 1), randomDay); + const randomCost = Math.round(Math.random() * 10000) / 100; tmpArray[i] = { id: i, @@ -360,7 +364,7 @@ export default class Example3 { percentComplete: Math.round(Math.random() * 100), start: new Date(randomYear, randomMonth, randomDay), finish: randomFinish < new Date() ? '' : randomFinish, // make sure the random date is earlier than today - cost: (i % 33 === 0) ? null : Math.round(Math.random() * 10000) / 100, + cost: (i % 33 === 0) ? -randomCost : randomCost, effortDriven: (i % 5 === 0) }; @@ -442,7 +446,7 @@ export default class Example3 { this.sgb?.slickGrid?.setPreHeaderPanelVisibility(!this.sgb?.slickGrid?.getOptions().showPreHeaderPanel); } - onGroupChanged(change: { caller?: string; groupColumns: Grouping[] }) { + onGroupChanged(change: { caller?: string; groupColumns: Grouping[]; }) { const caller = change && change.caller || []; const groups = change && change.groupColumns || []; diff --git a/packages/common/src/formatters/formatterUtilities.ts b/packages/common/src/formatters/formatterUtilities.ts index 552f07f10..8c9922cf2 100644 --- a/packages/common/src/formatters/formatterUtilities.ts +++ b/packages/common/src/formatters/formatterUtilities.ts @@ -137,14 +137,12 @@ export function getAssociatedDateFormatter(fieldType: typeof FieldType[keyof typ export function exportWithFormatterWhenDefined(row: number, col: number, columnDef: Column, dataContext: T, grid: SlickGrid, exportOptions?: TextExportOption | ExcelExportOption) { let isEvaluatingFormatter = false; - // first check if there are any export options provided (as Grid Options) - if (exportOptions?.hasOwnProperty('exportWithFormatter')) { - isEvaluatingFormatter = !!exportOptions.exportWithFormatter; - } - - // second check if "exportWithFormatter" is provided in the column definition, if so it will have precendence over the Grid Options exportOptions + // check if "exportWithFormatter" is provided in the column definition, if so it will have precendence over the Grid Options exportOptions if (columnDef?.hasOwnProperty('exportWithFormatter')) { isEvaluatingFormatter = !!columnDef.exportWithFormatter; + } else if (exportOptions?.hasOwnProperty('exportWithFormatter')) { + // last check in Grid Options export options + isEvaluatingFormatter = !!exportOptions.exportWithFormatter; } let formatter: Formatter | undefined; diff --git a/packages/excel-export/src/excelUtils.spec.ts b/packages/excel-export/src/excelUtils.spec.ts index 482fe52e6..3eed76921 100644 --- a/packages/excel-export/src/excelUtils.spec.ts +++ b/packages/excel-export/src/excelUtils.spec.ts @@ -47,6 +47,11 @@ describe('excelUtils', () => { expect(output).toEqual({ metadata: { style: 3 }, value: 1209.33 }); }); + it('should return negative parsed number when input value can be parsed to a number', () => { + const output = getExcelNumberCallback('-$1,209.33', {} as Column, 3, {}, mockGridOptions); + expect(output).toEqual({ metadata: { style: 3 }, value: -1209.33 }); + }); + it('should be able to provide a number with different decimal separator as formatter options and return parsed number when input value can be parsed to a number', () => { const output = getExcelNumberCallback( '1 244 209,33€', {} as Column, 3, {}, diff --git a/packages/excel-export/src/excelUtils.ts b/packages/excel-export/src/excelUtils.ts index 047f5eca4..5aec63d92 100644 --- a/packages/excel-export/src/excelUtils.ts +++ b/packages/excel-export/src/excelUtils.ts @@ -33,8 +33,8 @@ export function parseNumberWithFormatterOptions(value: any, column: Column, grid if (typeof value === 'string' && value) { const decimalSeparator = getValueFromParamsOrFormatterOptions('decimalSeparator', column, gridOptions, Constants.DEFAULT_NUMBER_DECIMAL_SEPARATOR); const val: number | string = (decimalSeparator === ',') - ? parseFloat(value.replace(/[^0-9\,]+/g, '').replace(',', '.')) - : parseFloat(value.replace(/[^\d\.]/g, '')); + ? parseFloat(value.replace(/[^0-9\,\-]+/g, '').replace(',', '.')) + : parseFloat(value.replace(/[^\d\.\-]/g, '')); outValue = isNaN(val) ? value : val; } return outValue;