fix(pivot-grid): fix date format based on the localization#17254
fix(pivot-grid): fix date format based on the localization#17254
Conversation
There was a problem hiding this comment.
Pull request overview
This PR addresses locale-dependent date display in the Pivot Grid by introducing a dimension-level display formatter and using it to render leaf date dimension headers in a locale-aware short-date format.
Changes:
- Added
IPivotDimension.formatterto support display-only formatting of dimension header values. - Updated row dimension header rendering to apply
dim.formatterwhen present. - Updated
IgxPivotDateDimensionto attach a locale-aware short-date formatter forfullDateleaf values (when no custommemberFunctionis provided), and adjusted a unit test expectation accordingly.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| projects/igniteui-angular/grids/pivot-grid/src/pivot-row-dimension-content.component.ts | Applies IPivotDimension.formatter when building row dimension header text. |
| projects/igniteui-angular/grids/pivot-grid/src/pivot-grid.spec.ts | Updates expected date header to be locale-derived rather than hardcoded. |
| projects/igniteui-angular/grids/core/src/pivot-grid.interface.ts | Adds new IPivotDimension.formatter API with documentation. |
| projects/igniteui-angular/grids/core/src/pivot-grid-dimensions.ts | Attaches a locale-aware short-date formatter to the full-date leaf dimension. |
| 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); |
There was a problem hiding this comment.
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.
| const formattedDate = Intl.DateTimeFormat(undefined, { dateStyle: 'short' }).format(new Date(2021, 11, 8)); | ||
| const expectedHeaders = ['All Periods', '2021', 'Q4', 'December', formattedDate]; |
There was a problem hiding this comment.
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').
| * // Display dates in a locale-aware short date format. | ||
| * { memberName: 'Date', enabled: true, formatter: (value) => new Date(value).toLocaleDateString() } | ||
| * ``` | ||
| */ |
There was a problem hiding this comment.
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.
| */ | |
| */ | |
| /* csTreatAsEvent: PivotDimensionFormatterEventHandler */ | |
| /* blazorOnlyScript */ |
| const dateValue = (value !== null && value !== undefined && value !== '') | ||
| ? getDateFormatter().createDateFromValue(value) | ||
| : null; | ||
| return dateValue | ||
| ? getDateFormatter().formatDateTime(dateValue, undefined, { dateStyle: 'short' }) | ||
| : value; |
There was a problem hiding this comment.
The added date formatter can return value when parsing fails/empty. Since IPivotDimension.formatter is typed to return string, returning null/undefined/non-string here breaks the contract and leaks through to rendering. Either ensure this formatter always returns a string (e.g. empty string / String(value)), or loosen the IPivotDimension.formatter return type to match the intended behavior.
| const dateValue = (value !== null && value !== undefined && value !== '') | |
| ? getDateFormatter().createDateFromValue(value) | |
| : null; | |
| return dateValue | |
| ? getDateFormatter().formatDateTime(dateValue, undefined, { dateStyle: 'short' }) | |
| : value; | |
| 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 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; |
There was a problem hiding this comment.
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.
| // When fullDate is enabled and the user has not provided a custom memberFunction, | ||
| // attach a locale-aware formatter so the leaf date values are displayed in | ||
| // short-date format instead of the raw data string. | ||
| // When the user provides their own memberFunction, the dimension is used as-is | ||
| // (spread-create is skipped) to avoid overriding the user's intended formatting. | ||
| let baseDimension: IPivotDimension = null; | ||
| if (options.fullDate) { | ||
| if (inBaseDimension.memberFunction) { | ||
| // User supplied a custom memberFunction — preserve it without adding a formatter. | ||
| baseDimension = inBaseDimension; | ||
| } else { | ||
| // No custom memberFunction: create a new dimension object with a locale-aware | ||
| // formatter that shows dates in short-date format. | ||
| baseDimension = { | ||
| ...inBaseDimension, | ||
| formatter: (value: any) => { | ||
| const dateValue = (value !== null && value !== undefined && value !== '') | ||
| ? getDateFormatter().createDateFromValue(value) | ||
| : null; | ||
| return dateValue | ||
| ? getDateFormatter().formatDateTime(dateValue, undefined, { dateStyle: 'short' }) | ||
| : value; | ||
| } | ||
| }; | ||
| } |
There was a problem hiding this comment.
IgxPivotDateDimension adds a default formatter by spreading inBaseDimension, which will overwrite a user-supplied inBaseDimension.formatter when fullDate is enabled. Also, skipping the formatter entirely when inBaseDimension.memberFunction is provided prevents localization in common cases where memberFunction is used only to extract a nested date field. Consider only adding the default formatter when inBaseDimension.formatter is not already set (and keep memberFunction intact), rather than gating on memberFunction or overriding an existing formatter.
There was a problem hiding this comment.
@copilot apply changes based on this feedback
There was a problem hiding this comment.
Fixed in commit 1027bbd. The logic now gates on inBaseDimension.formatter (not memberFunction): if the user already supplied a formatter it's preserved as-is; otherwise the default locale-aware short-date formatter is attached. memberFunction is kept intact in both paths via the spread.
…atter is not set; remove memberFunction gate Agent-Logs-Url: https://github.com/IgniteUI/igniteui-angular/sessions/6a4f5653-eb5e-4555-82d8-ad0464847dcf Co-authored-by: Hristo313 <57346540+Hristo313@users.noreply.github.com>
Closes #16442
Description
Adds a display-only formatter hook to IPivotDimension and uses it to localize the leaf-level fullDate values produced by IgxPivotDateDimension, so both row and column dimension headers show locale-aware short dates instead of raw ISO strings.
Motivation / Context
Type of Change (check all that apply):
Component(s) / Area(s) Affected:
How Has This Been Tested?
Test Configuration:
Screenshots / Recordings
Checklist:
feature/README.MDupdates for the feature docsREADME.MDCHANGELOG.MDupdates for newly added functionalityng updatemigrations for the breaking changes (migrations guidelines)