ag-grid
Version:
Advanced Data Grid / Data Table supporting Javascript / React / AngularJS / Web Components
162 lines (133 loc) • 6.66 kB
text/typescript
import {RowNode} from "../entities/rowNode";
import {Column} from "../entities/column";
import {Autowired, Bean, PostConstruct} from "../context/context";
import {SortController} from "../sortController";
import {_} from "../utils";
import {ValueService} from "../valueService/valueService";
import {GridOptionsWrapper} from "../gridOptionsWrapper";
import {ColumnController} from "../columnController/columnController";
export interface SortOption {
inverter: number;
column: Column;
}
export interface SortedRowNode {
currentPos: number;
rowNode: RowNode;
}
('sortService')
export class SortService {
('sortController') private sortController: SortController;
('columnController') private columnController: ColumnController;
('valueService') private valueService: ValueService;
('gridOptionsWrapper') private gridOptionsWrapper: GridOptionsWrapper;
private postSortFunc: (rowNodes: RowNode[]) => void;
public init(): void {
this.postSortFunc = this.gridOptionsWrapper.getPostSortFunc();
}
public sortAccordingToColumnsState(rowNode: RowNode) {
let sortOptions: SortOption[] = this.sortController.getSortForRowController();
this.sort(rowNode, sortOptions);
}
public sort(rowNode: RowNode, sortOptions: SortOption[]) {
rowNode.childrenAfterSort = rowNode.childrenAfterFilter.slice(0);
// we clear out the 'pull down open parents' first, as the values mix up the sorting
this.pullDownDataForHideOpenParents(rowNode, true);
let sortActive = _.exists(sortOptions) && sortOptions.length > 0;
if (sortActive) {
// RE https://ag-grid.atlassian.net/browse/AG-444
//Javascript sort is non deterministic when all the array items are equals
//ie Comparator always returns 0, so if you want to ensure the array keeps its
//order, then you need to add an additional sorting condition manually, in this
//case we are going to inspect the original array position
let sortedRowNodes: SortedRowNode[] = rowNode.childrenAfterSort.map((it, pos) => {
return {currentPos: pos, rowNode: it};
});
sortedRowNodes.sort(this.compareRowNodes.bind(this, sortOptions));
rowNode.childrenAfterSort = sortedRowNodes.map(sorted => sorted.rowNode);
}
this.updateChildIndexes(rowNode);
this.pullDownDataForHideOpenParents(rowNode, false);
// sort any groups recursively
rowNode.childrenAfterFilter.forEach(child => {
if (child.hasChildren()) {
this.sort(child, sortOptions);
}
});
if (this.postSortFunc) {
this.postSortFunc(rowNode.childrenAfterSort);
}
}
private compareRowNodes(sortOptions: any, sortedNodeA: SortedRowNode, sortedNodeB: SortedRowNode) {
let nodeA: RowNode = sortedNodeA.rowNode;
let nodeB: RowNode = sortedNodeB.rowNode;
// Iterate columns, return the first that doesn't match
for (let i = 0, len = sortOptions.length; i < len; i++) {
let sortOption = sortOptions[i];
// let compared = compare(nodeA, nodeB, sortOption.column, sortOption.inverter === -1);
let isInverted = sortOption.inverter === -1;
let valueA: any = this.getValue(nodeA, sortOption.column);
let valueB: any = this.getValue(nodeB, sortOption.column);
let comparatorResult: number;
if (sortOption.column.getColDef().comparator) {
//if comparator provided, use it
comparatorResult = sortOption.column.getColDef().comparator(valueA, valueB, nodeA, nodeB, isInverted);
} else {
//otherwise do our own comparison
comparatorResult = _.defaultComparator(valueA, valueB, this.gridOptionsWrapper.isAccentedSort());
}
if (comparatorResult !== 0) {
return comparatorResult * sortOption.inverter;
}
}
// All matched, we make is so that the original sort order is kept:
return sortedNodeA.currentPos - sortedNodeB.currentPos;
}
private getValue(nodeA: RowNode, column: Column): string {
return this.valueService.getValue(column, nodeA);
}
private updateChildIndexes(rowNode: RowNode) {
if (_.missing(rowNode.childrenAfterSort)) {
return;
}
rowNode.childrenAfterSort.forEach((child: RowNode, index: number) => {
let firstChild = index === 0;
let lastChild = index === rowNode.childrenAfterSort.length - 1;
child.setFirstChild(firstChild);
child.setLastChild(lastChild);
child.setChildIndex(index);
});
}
private pullDownDataForHideOpenParents(rowNode: RowNode, clearOperation: boolean) {
if (_.missing(rowNode.childrenAfterSort)) {
return;
}
if (!this.gridOptionsWrapper.isGroupHideOpenParents()) {
return;
}
rowNode.childrenAfterSort.forEach( childRowNode => {
let groupDisplayCols = this.columnController.getGroupDisplayColumns();
groupDisplayCols.forEach( groupDisplayCol => {
let showRowGroup = groupDisplayCol.getColDef().showRowGroup;
if (typeof showRowGroup !== 'string') {
console.error('ag-Grid: groupHideOpenParents only works when specifying specific columns for colDef.showRowGroup');
return;
}
let displayingGroupKey: string = <string> showRowGroup;
let rowGroupColumn = this.columnController.getPrimaryColumn(displayingGroupKey);
let thisRowNodeMatches = rowGroupColumn === childRowNode.rowGroupColumn;
if (thisRowNodeMatches) { return; }
if (clearOperation) {
// if doing a clear operation, we clear down the value for every possible group column
childRowNode.setGroupValue(groupDisplayCol.getId(), null);
} else {
// if doing a set operation, we set only where the pull down is to occur
let parentToStealFrom = childRowNode.getFirstChildOfFirstChild(rowGroupColumn);
if (parentToStealFrom) {
childRowNode.setGroupValue(groupDisplayCol.getId(), parentToStealFrom.key);
}
}
});
});
}
}