Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 32 additions & 7 deletions projects/igniteui-angular/grids/core/src/pivot-grid-dimensions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,13 +139,38 @@ export class IgxPivotDateDimension implements IPivotDimension {
this.enabled = inBaseDimension.enabled;
this.displayName = inBaseDimension.displayName || this.resourceStrings.igx_grid_pivot_date_dimension_total;

const baseDimension = options.fullDate ? inBaseDimension : null;
// When fullDate is enabled, attach a locale-aware formatter unless the user has
// already supplied their own formatter on inBaseDimension.
// The memberFunction (if any) is kept intact via the spread — the formatter is
// a separate display-only concern and should not be gated on memberFunction.
let baseDimension: IPivotDimension = null;
if (options.fullDate) {
if (inBaseDimension.formatter) {
// User supplied their own formatter — use the dimension as-is.
baseDimension = inBaseDimension;
} else {
// No user-supplied formatter: create a new dimension object with a locale-aware
// formatter that shows dates in short-date format.
baseDimension = {
...inBaseDimension,
formatter: (value: any) => {
const hasValue = value !== null && value !== undefined && value !== '';
const dateValue = hasValue ? getDateFormatter().createDateFromValue(value) : null;
if (dateValue) {
return getDateFormatter().formatDateTime(dateValue, undefined, { dateStyle: 'short' });
}
return hasValue ? String(value) : '';
}
Comment on lines +156 to +163
Copy link

Copilot AI Apr 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getDateFormatter() is called twice per formatted cell. If formatter is invoked frequently (row header rendering/virtualization), this adds avoidable overhead. Capture the formatter instance once in the closure (or outside the callback) and reuse it for both createDateFromValue and formatDateTime.

Copilot uses AI. Check for mistakes.
};
}
}
Comment on lines +147 to +166
Copy link

Copilot AI Apr 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New branching behavior is introduced for options.fullDate based on whether inBaseDimension.memberFunction is provided. The updated spec covers locale formatting, but it doesn’t appear to cover the memberFunction branch (ensuring no formatter is attached/used). Add a unit test that sets fullDate: true with a custom memberFunction and asserts header rendering behaves as intended for that path.

Copilot uses AI. Check for mistakes.

const monthDimensionDef: IPivotDimension = {
memberName: 'Months',
memberFunction: (rec) => {
const recordValue = PivotUtil.extractValueFromDimension(inBaseDimension, rec);
const dateValue = recordValue ? getDateFormatter().createDateFromValue(recordValue) : null;
return recordValue ? getDateFormatter().formatDateTime(dateValue, undefined, { month: 'long'}) : rec['Months'];
const dateValue = (recordValue != null && recordValue !== '') ? getDateFormatter().createDateFromValue(recordValue) : null;
return (recordValue != null && recordValue !== '') ? getDateFormatter().formatDateTime(dateValue, undefined, { month: 'long'}) : rec['Months'];
},
enabled: true,
childLevel: baseDimension
Expand All @@ -156,8 +181,8 @@ export class IgxPivotDateDimension implements IPivotDimension {
memberName: 'Quarters',
memberFunction: (rec) => {
const recordValue = PivotUtil.extractValueFromDimension(inBaseDimension, rec);
const dateValue = recordValue ? getDateFormatter().createDateFromValue(recordValue) : null;
return recordValue ? `Q` + Math.ceil((dateValue.getMonth() + 1) / 3) : rec['Quarters'];
const dateValue = (recordValue != null && recordValue !== '') ? getDateFormatter().createDateFromValue(recordValue) : null;
return (recordValue != null && recordValue !== '') ? `Q` + Math.ceil((dateValue.getMonth() + 1) / 3) : rec['Quarters'];
},
enabled: true,
childLevel: monthDimension
Expand All @@ -168,8 +193,8 @@ export class IgxPivotDateDimension implements IPivotDimension {
memberName: 'Years',
memberFunction: (rec) => {
const recordValue = PivotUtil.extractValueFromDimension(inBaseDimension, rec);
const dateValue = recordValue ? getDateFormatter().createDateFromValue(recordValue) : null;
return recordValue ? dateValue.getFullYear().toString() : rec['Years'];
const dateValue = (recordValue != null && recordValue !== '') ? getDateFormatter().createDateFromValue(recordValue) : null;
return (recordValue != null && recordValue !== '') ? dateValue.getFullYear().toString() : rec['Years'];
},
enabled: true,
childLevel: quarterDimension
Expand Down
16 changes: 16 additions & 0 deletions projects/igniteui-angular/grids/core/src/pivot-grid.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,22 @@ export interface IPivotDimension {
/** @hidden @internal */
autoWidth?: number;
horizontalSummary? : boolean;
/**
* Optional function to format the display value of a dimension cell.
* Unlike `memberFunction`, this does not affect the data key used for grouping or sorting —
* it is applied when rendering the dimension header text (both row and column dimension headers).
* When set, the return value of this function is shown instead of the raw dimension value.
* Return `null` or `undefined` to fall back to the raw value.
*
* @example
* ```typescript
Comment thread
Hristo313 marked this conversation as resolved.
* // Display dates in a locale-aware short date format.
* { memberName: 'Date', enabled: true, formatter: (value) => new Date(value).toLocaleDateString() }
* ```
*/
/* csTreatAsEvent: PivotDimensionFormatterEventHandler */
/* blazorOnlyScript */
formatter?: (value: any) => string | null | undefined;
}

/* marshalByValue */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2380,7 +2380,9 @@ export class IgxPivotGridComponent extends IgxGridBaseDirective implements OnIni
const ref = isGroup ?
createComponent(IgxColumnGroupComponent, { environmentInjector: this.envInjector, elementInjector: this.injector }) :
createComponent(IgxColumnComponent, { environmentInjector: this.envInjector, elementInjector: this.injector });
ref.instance.header = parent != null ? key.split(parent.header + this.pivotKeys.columnDimensionSeparator)[1] : key;
const rawHeader = parent != null ? key.split(parent.field + this.pivotKeys.columnDimensionSeparator)[1] : key;
const dim = value.dimension as IPivotDimension;
ref.instance.header = dim?.formatter != null ? (dim.formatter(rawHeader) ?? rawHeader) : rawHeader;
ref.instance.field = key;
ref.instance.parent = parent;
if (value.dimension.width) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1245,7 +1245,8 @@ describe('IgxPivotGrid #pivotGrid', () => {
// check rows
const rows = pivotGrid.rowList.toArray();
expect(rows.length).toBe(5);
const expectedHeaders = ['All Periods', '2021', 'Q4', 'December', '12/08/2021'];
const formattedDate = Intl.DateTimeFormat(undefined, { dateStyle: 'short' }).format(new Date(2021, 11, 8));
const expectedHeaders = ['All Periods', '2021', 'Q4', 'December', formattedDate];
Comment on lines +1248 to +1249
Copy link

Copilot AI Apr 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The production code formats via getDateFormatter().formatDateTime(..., { dateStyle: 'short' }), while the test computes expectations using Intl.DateTimeFormat(...). These can differ across environments/locales/formatting backends even when both are 'short'. To avoid CI flakiness, compute formattedDate using the same date formatting utility used by the component (or explicitly set/override the test locale to a known value and assert that exact string).

Copilot uses AI. Check for mistakes.
const rowHeaders = fixture.debugElement.queryAll(
By.directive(IgxPivotRowDimensionHeaderComponent));
const rowDimensionHeaders = rowHeaders.map(x => x.componentInstance.column.header);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,11 @@ export class IgxPivotRowDimensionContentComponent extends IgxGridHeaderRowCompon

protected extractFromDimension(dim: IPivotDimension, rowData: IPivotGridGroupRecord) {
const field = dim.memberName;
const header = rowData?.dimensionValues.get(field);
const rawHeader = rowData?.dimensionValues.get(field);
let header = rawHeader;
if (dim.formatter != null) {
header = dim.formatter(rawHeader) ?? rawHeader;
Copy link

Copilot AI Apr 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new dimension formatter is invoked with only the raw value, which makes it less capable than other grid formatter patterns (often providing row/column context). Since this is a new API surface, consider extending the signature to accept context (e.g., row group record and/or dimension) and pass it here, so consumers can format based on locale and/or other dimension values without relying on external closures.

Suggested change
header = dim.formatter(rawHeader) ?? rawHeader;
const formatter = dim.formatter as (value: any, dimension?: IPivotDimension, record?: IPivotGridGroupRecord) => any;
header = formatter(rawHeader, dim, rowData) ?? rawHeader;

Copilot uses AI. Check for mistakes.
}
const col = this._createColComponent(field, header, dim);
return col;
}
Expand Down
Loading