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) : '';
}
};
}
}

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
* // Display dates in a locale-aware short date format.
* { memberName: 'Date', enabled: true, formatter: (value) => new Date(value).toLocaleDateString() }
* ```
*/
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.

IPivotDimension.formatter is a function-valued API surface similar to memberFunction and IPivotValue.formatter, but it currently lacks the interop/codegen annotations used elsewhere in this interface (e.g. /* csTreatAsEvent */, /* blazorOnlyScript */). If these markers are required for your generated wrappers, please add the appropriate annotations for formatter as well to avoid breaking non-TS consumers.

Suggested change
*/
*/
/* csTreatAsEvent: PivotDimensionFormatterEventHandler */
/* blazorOnlyScript */

Copilot uses AI. Check for mistakes.
/* 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;
Comment on lines +2383 to 2386
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 behavior applies IPivotDimension.formatter to column dimension headers (createColumnForDimension). There’s no unit test coverage ensuring the formatter is applied for column headers (and that null/undefined falls back to the raw header) similar to the added row-header coverage. Add a spec that configures a column dimension with a formatter and asserts the rendered column/group header text reflects it.

Copilot uses AI. Check for mistakes.
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.

This test derives the expected formatted date using Intl.DateTimeFormat(...).format(new Date(...)), but the production code formats by parsing the raw string via getDateFormatter().createDateFromValue(...) and then formatDateTime(...). To keep the assertion aligned with the actual code path (and avoid differences in parsing assumptions), compute the expected value using the same getDateFormatter() logic starting from the raw sample string (e.g. '12/08/2021').

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;
}
const col = this._createColComponent(field, header, dim);
Comment on lines 184 to 191
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.

IPivotDimension.formatter is documented as affecting “dimension header text” generally, but the implementation is currently only applied for row dimension headers. This means the same dimension used in the column hierarchy (or other UI that renders dimension values) will still display the raw value, which is inconsistent with the API docs. Consider either applying the formatter consistently wherever dimension header text is derived, or clarifying in the docs/API that it is row-header-only.

Copilot uses AI. Check for mistakes.
return col;
}
Expand Down
Loading