Skip to content

fix(pivot-grid): Handle currency pivot values with count aggregator - 19.2.x #15428

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Jun 27, 2025
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import { IgxIconComponent } from "../../icon/icon.component";
import { IgxInputGroupComponent } from "../../input-group/input-group.component";
import { fadeIn, fadeOut } from 'igniteui-angular/animations';
import { Size } from '../common/enums';
import { GridColumnDataType } from '../../data-operations/data-util';

interface IDataSelectorPanel {
name: string;
Expand Down Expand Up @@ -541,8 +542,13 @@ export class IgxPivotDataSelectorComponent {
* @internal
*/
public onAggregationChange(event: ISelectionEventArgs) {

if (!this.isSelected(event.newSelection.value)) {
this.value.aggregate = event.newSelection.value;
const isSingleValue = this.grid.values.length === 1;

PivotUtil.updateColumnTypeByAggregator(this.grid.columns, this.value, isSingleValue);

this.grid.pipeTrigger++;
this.grid.cdr.markForCheck();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,12 @@ import {
} from '@angular/core';
import { DOCUMENT, NgTemplateOutlet, NgClass, NgStyle } from '@angular/common';

import { first, take, takeUntil} from 'rxjs/operators';
import { first, take, takeUntil } from 'rxjs/operators';
import { IgxGridBaseDirective } from '../grid-base.directive';
import { IgxFilteringService } from '../filtering/grid-filtering.service';
import { IgxGridSelectionService } from '../selection/selection.service';
import { IgxForOfSyncService, IgxForOfScrollSyncService } from '../../directives/for-of/for_of.sync.service';
import { ColumnType, GridType, IGX_GRID_BASE, IGX_GRID_SERVICE_BASE, IgxColumnTemplateContext, RowType } from '../common/grid.interface';
import { ColumnType, GridType, IGX_GRID_BASE, IGX_GRID_SERVICE_BASE, IgxColumnTemplateContext, PivotGridType, RowType } from '../common/grid.interface';
import { IgxGridCRUDService } from '../common/crud.service';
import { IgxGridSummaryService } from '../summaries/grid-summary.service';
import { DEFAULT_PIVOT_KEYS, IDimensionsChange, IgxPivotGridValueTemplateContext, IPivotConfiguration, IPivotConfigurationChangedEventArgs, IPivotDimension, IPivotValue, IValuesChange, PivotDimensionType, IPivotUISettings, PivotRowLayoutType, PivotSummaryPosition } from './pivot-grid.interface';
Expand Down Expand Up @@ -71,7 +71,7 @@ import { IgxPivotColumnResizingService } from '../resizing/pivot-grid/pivot-resi
import { IgxFlatTransactionFactory, IgxOverlayService, State, Transaction, TransactionService } from '../../services/public_api';
import { cloneArray, PlatformUtil, resizeObservable } from '../../core/utils';
import { IgxPivotFilteringService } from './pivot-filtering.service';
import { DataUtil } from '../../data-operations/data-util';
import { DataUtil, GridColumnDataType } from '../../data-operations/data-util';
import { IFilteringExpressionsTree } from '../../data-operations/filtering-expressions-tree';
import { IgxGridTransaction } from '../common/types';
import { GridBaseAPIService } from '../api.service';
Expand Down Expand Up @@ -197,7 +197,7 @@ const MINIMUM_COLUMN_WIDTH_SUPER_COMPACT = 104;
schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class IgxPivotGridComponent extends IgxGridBaseDirective implements OnInit, AfterContentInit,
GridType, AfterViewInit, OnChanges {
PivotGridType, AfterViewInit, OnChanges {

/**
* Emitted when the dimension collection is changed via the grid chip area.
Expand Down Expand Up @@ -1665,7 +1665,7 @@ export class IgxPivotGridComponent extends IgxGridBaseDirective implements OnIni
public autoSizeRowDimension(dimension: IPivotDimension) {
if (this.getDimensionType(dimension) === PivotDimensionType.Row) {
const relatedDims: string[] = PivotUtil.flatten([dimension]).map((x: IPivotDimension) => x.memberName);
const contentCollection = this.getContentCollection(dimension);
const contentCollection = this.getContentCollection(dimension);
const content = contentCollection.filter(x => relatedDims.indexOf(x.dimension.memberName) !== -1);
const headers = content.map(x => x.headerGroups.toArray()).flat().map(x => x.header && x.header.refInstance);
if (this.pivotUI.showRowHeaders) {
Expand Down Expand Up @@ -1939,8 +1939,8 @@ export class IgxPivotGridComponent extends IgxGridBaseDirective implements OnIni
*/
public getRowDimensionByName(memberName: string) {
const visibleRows = this.pivotUI.rowLayout === PivotRowLayoutType.Vertical ?
this.pivotConfiguration.rows :
PivotUtil.flatten(this.pivotConfiguration.rows);
this.pivotConfiguration.rows :
PivotUtil.flatten(this.pivotConfiguration.rows);
const dimIndex = visibleRows.findIndex((target) => target.memberName === memberName);
const dim = visibleRows[dimIndex];
return dim;
Expand Down Expand Up @@ -2264,7 +2264,7 @@ export class IgxPivotGridComponent extends IgxGridBaseDirective implements OnIni
const separator = this.pivotKeys.columnDimensionSeparator;
const dataArr = fields.map(x => x.split(separator)).sort(x => x.length);
const hierarchy = new Map<string, any>();
const columnDimensions = PivotUtil.flatten(this.columnDimensions);
const columnDimensions = PivotUtil.flatten(this.columnDimensions);
dataArr.forEach(arr => {
let currentHierarchy = hierarchy;
const path = [];
Expand All @@ -2284,17 +2284,22 @@ export class IgxPivotGridComponent extends IgxGridBaseDirective implements OnIni
});
return hierarchy;
}

protected generateColumnHierarchy(fields: Map<string, any>, data, parent = null): IgxColumnComponent[] {
let columns = [];
if (fields.size === 0) {
this.values.forEach((value) => {
const ref = createComponent(IgxColumnComponent, { environmentInjector: this.envInjector, elementInjector: this.injector });
let columnDataType = value.dataType || this.resolveDataTypes(data.length ? data[0][value.member] : null);

if (value.aggregate?.key?.toLowerCase() === 'count' && (columnDataType === GridColumnDataType.Currency || columnDataType == GridColumnDataType.Percent)) {
columnDataType = GridColumnDataType.Number;
}

ref.instance.header = value.displayName;
ref.instance.field = value.member;
ref.instance.parent = parent;
ref.instance.sortable = true;
ref.instance.dataType = value.dataType || this.resolveDataTypes(data.length ? data[0][value.member] : null);
ref.instance.dataType = columnDataType;
ref.instance.formatter = value.formatter;
columns.push(ref.instance);
});
Expand All @@ -2308,9 +2313,20 @@ export class IgxPivotGridComponent extends IgxGridBaseDirective implements OnIni
}
if (shouldGenerate && (value.children == null || value.children.length === 0 || value.children.size === 0)) {
const col = this.createColumnForDimension(value, data, parent, this.hasMultipleValues);

if (!this.hasMultipleValues && this.values.length > 0) {
PivotUtil.updateColumnTypeByAggregator([col], this.values[0], true);
}

columns.push(col);
if (this.hasMultipleValues) {
const measureChildren = this.getMeasureChildren(data, col, false, value.dimension.width);

measureChildren.forEach((child, index) => {
const pivotValue = this.values[index];
PivotUtil.updateColumnTypeByAggregator([child], pivotValue, this.values.length === 1);
});

col.children.reset(measureChildren);
columns = columns.concat(measureChildren);
}
Expand Down Expand Up @@ -2380,20 +2396,20 @@ export class IgxPivotGridComponent extends IgxGridBaseDirective implements OnIni
};
values.push(value);
break;
}
case "date":
{
const dimension: IPivotDimension = new IgxPivotDateDimension(
}
case "date":
{
memberName: field,
enabled: isFirstDate,
dataType: dataType
const dimension: IPivotDimension = new IgxPivotDateDimension(
{
memberName: field,
enabled: isFirstDate,
dataType: dataType
}
)
rowDimensions.push(dimension);
isFirstDate = false;
break;
}
)
rowDimensions.push(dimension);
isFirstDate = false;
break;
}
default: {
const dimension: IPivotDimension = {
memberName: field,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import { IgxDropDirective } from '../../directives/drag-drop/drag-drop.directive
import { NgTemplateOutlet, NgClass, NgStyle } from '@angular/common';
import { IgxPivotRowHeaderGroupComponent } from './pivot-row-header-group.component';
import { IgxPivotRowDimensionHeaderGroupComponent } from './pivot-row-dimension-header-group.component';
import { GridColumnDataType } from '../../data-operations/data-util';

/**
*
Expand Down Expand Up @@ -137,7 +138,7 @@ export class IgxPivotHeaderRowComponent extends IgxGridHeaderRowComponent implem
@Inject(IGX_GRID_BASE) public override grid: PivotGridType,
ref: ElementRef<HTMLElement>,
cdr: ChangeDetectorRef,
protected renderer: Renderer2,
protected renderer: Renderer2
) {
super(ref, cdr);
}
Expand Down Expand Up @@ -407,8 +408,13 @@ export class IgxPivotHeaderRowComponent extends IgxGridHeaderRowComponent implem
* @internal
*/
public onAggregationChange(event: ISelectionEventArgs) {

if (!this.isSelected(event.newSelection.value)) {
this.value.aggregate = event.newSelection.value;
const isSingleValue = this.grid.values.length === 1;

PivotUtil.updateColumnTypeByAggregator(this.grid.columns, this.value, isSingleValue);

this.grid.pipeTrigger++;
}
}
Expand Down
37 changes: 28 additions & 9 deletions projects/igniteui-angular/src/lib/grids/pivot-grid/pivot-util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { DataUtil, GridColumnDataType } from '../../data-operations/data-util';
import { FilteringLogic } from '../../data-operations/filtering-expression.interface';
import { FilteringExpressionsTree } from '../../data-operations/filtering-expressions-tree';
import { ISortingExpression } from '../../data-operations/sorting-strategy';
import { PivotGridType } from '../common/grid.interface';
import { ColumnType, PivotGridType } from '../common/grid.interface';
import { IGridSortingStrategy, IgxSorting } from '../common/strategy';
import { IgxPivotAggregate, IgxPivotDateAggregate, IgxPivotNumericAggregate, IgxPivotTimeAggregate } from './pivot-grid-aggregate';
import { IPivotAggregator, IPivotConfiguration, IPivotDimension, IPivotGridRecord, IPivotKeys, IPivotValue, PivotDimensionType, PivotSummaryPosition } from './pivot-grid.interface';
Expand Down Expand Up @@ -88,13 +88,13 @@ export class PivotUtil {
}

public static flattenGroupsHorizontally(data: IPivotGridRecord[],
dimension: IPivotDimension,
expansionStates,
defaultExpand: boolean,
visibleDimensions: IPivotDimension[],
summariesPosition: PivotSummaryPosition,
parent?: IPivotDimension,
parentRec?: IPivotGridRecord) {
dimension: IPivotDimension,
expansionStates,
defaultExpand: boolean,
visibleDimensions: IPivotDimension[],
summariesPosition: PivotSummaryPosition,
parent?: IPivotDimension,
parentRec?: IPivotGridRecord) {
for (let i = 0; i < data.length; i++) {
const rec = data[i];
const field = dimension.memberName;
Expand Down Expand Up @@ -316,7 +316,7 @@ export class PivotUtil {
const aggregationKey = groupName ? groupName + pivotKeys.columnDimensionSeparator + key : key;
rec.aggregationValues.set(aggregationKey, aggregationData[key]);
});
} else if (aggregationKeys.length === 1) {
} else if (aggregationKeys.length === 1) {
const aggregationKey = aggregationKeys[0];
rec.aggregationValues.set(groupName || aggregationKey, aggregationData[aggregationKey]);
}
Expand Down Expand Up @@ -508,5 +508,24 @@ export class PivotUtil {
}
}

public static updateColumnTypeByAggregator(columns: any[], value: IPivotValue, isSingleValue: boolean): void {
const targetColumnType = PivotUtil.getColumnDataTypeForValue(value);
columns.forEach(column => {
if ((column.field?.includes(value.member) || isSingleValue) && targetColumnType !== undefined) {
column.dataType = targetColumnType;
}
})
}

private static getColumnDataTypeForValue(value: IPivotValue): GridColumnDataType {
const isCountAggregator = value.aggregate.aggregator?.name?.toLowerCase() === 'count' || value.aggregate.aggregatorName?.toLowerCase() === 'count';

if ((value.dataType === GridColumnDataType.Currency || value.dataType === GridColumnDataType.Percent) && isCountAggregator) {
Copy link
Contributor

Choose a reason for hiding this comment

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

These checks are a bit repetitive as is the code in the ```if``'s. The same ones are in updateColumnDataTypeByAggregator and in `generateColumnHierarchy`. Maybe just extract it in a common util method that gets the column type for a given PivotValue and reuse it. It would also make the code a bit more readable:

public static updateColumnTypeByAggregator(columns: ColumnType[], value: IPivotValue, isSingleValue: boolean): void {
  const targetColumnType = getColumnDataTypeForValue(value);   
   columns.forEach(column => {
                  if (column.field?.includes(value.member) || isSingleValue) {
                      column.dataType = targetColumnType;
                  }  
              });
}

return GridColumnDataType.Number;
} else if (value.dataType === GridColumnDataType.Currency && !isCountAggregator) {
return GridColumnDataType.Currency;
} else if (value.dataType === GridColumnDataType.Percent && !isCountAggregator) {
return GridColumnDataType.Percent;
}
}
}
Loading