ag-grid-enterprise
Version:
ag-Grid Enterprise Features
177 lines (141 loc) • 6.25 kB
text/typescript
import {
Autowired,
Bean,
ChangedPath,
ColDef,
ColGroupDef,
Column,
ColumnController,
EventService,
IRowModel,
IRowNodeStage,
RowNode,
StageExecuteParams,
Utils,
ValueService
} from "ag-grid-community";
import {PivotColDefService} from "./pivotColDefService";
export class PivotStage implements IRowNodeStage {
// these should go into the pivot column creator
private rowModel: IRowModel;
private valueService: ValueService;
private columnController: ColumnController;
private eventService: EventService;
private pivotColDefService: PivotColDefService;
private uniqueValues: any = {};
private pivotColumnGroupDefs: (ColDef | ColGroupDef)[];
private pivotColumnDefs: ColDef[];
private aggregationColumnsHashLastTime: string | null;
private aggregationFuncsHashLastTime: string;
public execute(params: StageExecuteParams): void {
let rootNode = params.rowNode;
let changedPath = params.changedPath;
if (this.columnController.isPivotActive()) {
this.executePivotOn(rootNode, changedPath);
} else {
this.executePivotOff(changedPath);
}
}
private executePivotOff(changedPath: ChangedPath | undefined): void {
this.aggregationColumnsHashLastTime = null;
this.uniqueValues = {};
if (this.columnController.isSecondaryColumnsPresent()) {
this.columnController.setSecondaryColumns(null, "rowModelUpdated");
if (changedPath) {
changedPath.setInactive();
}
}
}
private executePivotOn(rootNode: RowNode, changedPath: ChangedPath | undefined): void {
let uniqueValues = this.bucketUpRowNodes(rootNode);
let uniqueValuesChanged = this.setUniqueValues(uniqueValues);
let aggregationColumns = this.columnController.getValueColumns();
let aggregationColumnsHash = aggregationColumns.map((column) => column.getId()).join('#');
let aggregationFuncsHash = aggregationColumns.map((column) => column.getAggFunc().toString()).join('#');
let aggregationColumnsChanged = this.aggregationColumnsHashLastTime !== aggregationColumnsHash;
let aggregationFuncsChanged = this.aggregationFuncsHashLastTime !== aggregationFuncsHash;
this.aggregationColumnsHashLastTime = aggregationColumnsHash;
this.aggregationFuncsHashLastTime = aggregationFuncsHash;
if (uniqueValuesChanged || aggregationColumnsChanged || aggregationFuncsChanged) {
let result = this.pivotColDefService.createPivotColumnDefs(this.uniqueValues);
this.pivotColumnGroupDefs = result.pivotColumnGroupDefs;
this.pivotColumnDefs = result.pivotColumnDefs;
this.columnController.setSecondaryColumns(this.pivotColumnGroupDefs, "rowModelUpdated");
// because the secondary columns have changed, then the aggregation needs to visit the whole
// tree again, so we make the changedPath not active, to force aggregation to visit all paths.
if (changedPath) {
changedPath.setInactive();
}
}
}
private setUniqueValues(newValues: any): boolean {
let json1 = JSON.stringify(newValues);
let json2 = JSON.stringify(this.uniqueValues);
let uniqueValuesChanged = json1 !== json2;
// we only continue the below if the unique values are different, as otherwise
// the result will be the same as the last time we did it
if (uniqueValuesChanged) {
this.uniqueValues = newValues;
return true;
} else {
return false;
}
}
// returns true if values were different
private bucketUpRowNodes(rootNode: RowNode): any {
// accessed from inside inner function
let uniqueValues: any = {};
// finds all leaf groups and calls mapRowNode with it
let recursivelySearchForLeafNodes = (rowNode: RowNode) => {
if (rowNode.leafGroup) {
this.bucketRowNode(rowNode, uniqueValues);
} else {
rowNode.childrenAfterFilter.forEach(child => {
recursivelySearchForLeafNodes(child);
});
}
};
recursivelySearchForLeafNodes(rootNode);
return uniqueValues;
}
private bucketRowNode(rowNode: RowNode, uniqueValues: any): void {
let pivotColumns = this.columnController.getPivotColumns();
if (pivotColumns.length === 0) {
rowNode.childrenMapped = null;
return;
}
rowNode.childrenMapped = this.bucketChildren(rowNode.childrenAfterFilter, pivotColumns, 0, uniqueValues);
}
private bucketChildren(children: RowNode[], pivotColumns: Column[], pivotIndex: number, uniqueValues: any): any {
let mappedChildren: any = {};
let pivotColumn = pivotColumns[pivotIndex];
// map the children out based on the pivot column
children.forEach((child: RowNode) => {
let key: string = this.valueService.getKeyForNode(pivotColumn, child);
if (Utils.missing(key)) {
key = '';
}
if (!uniqueValues[key]) {
uniqueValues[key] = {};
}
if (!mappedChildren[key]) {
mappedChildren[key] = [];
}
mappedChildren[key].push(child);
});
// if it's the last pivot column, return as is, otherwise go one level further in the map
if (pivotIndex === pivotColumns.length - 1) {
return mappedChildren;
} else {
let result: any = {};
Utils.iterateObject(mappedChildren, (key: string, value: RowNode[]) => {
result[key] = this.bucketChildren(value, pivotColumns, pivotIndex + 1, uniqueValues[key]);
});
return result;
}
}
public getPivotColumnDefs(): ColDef[] {
return this.pivotColumnDefs;
}
}