TL;DR: How do you change what field to sort by at runtime (given: cell uses multiple values)
Currently I am creating an ag-grid in Angular that has columns where multiple data points are used for a given cell (valueGetter). Given this, I would want to allow the user the ability to sort based on whichever field they wanted to.
Currently, I was able to have a workaround where I override the column menu to show the specific fields for a given column (which has room for improvement to become more generic for all columns, but that's a different topic). I provided a function to this which would update the column definitions, replacing the comparator that was there originally, and refresh the column defs.
This (updating column defs) isn't ideal, because it closes the filters currently open in the side-bar. So my question is: is there a better way to go about changing what you sort by at runtime for a given column (not updating column defs)? Pretty niche use case but here's the relevant code that I mentioned above:
override the menu items:
getMainMenuItems(params) {
const defaultMenuItems = [];
switch(params.column.getId()) {
case 'product':
defaultMenuItems.push(
{
name: 'Sort By Customer',
action: () => this.updateComparatorOnColDef('customer', 'issuer'),
checked: params.column.userProvidedColDef.sortBy === 'customer'
},
{
name: 'Sort By Product Type',
action: () => this.updateComparatorOnColDef('product', 'productType'),
checked: params.column.userProvidedColDef.sortBy === 'productType'
},
{
name: 'Sort By ProductID',
action: () => this.updateComparatorOnColDef('product', 'productId'),
checked: params.column.userProvidedColDef.sortBy === 'productId'
},
);
return defaultMenuItems;
default:
return params.defaultItems;
}
}
update column definitions
updateComparatorOnColDef(colId: string, dataProperty: string) {
const newColDefs = _.cloneDeep(this.columnDefs);
const colDef = newColDefs.find(x => x.colId === colId);
if(colDef?.comparator) {
colDef.comparator = (valueA, valueB, nodeA, nodeB, isInverted) => {
if(typeof valueB[dataProperty] === 'string' && typeof valueA[dataProperty] === 'string') {
return ((valueA[dataProperty].toLowerCase()) > (valueB[dataProperty].toLowerCase())) ? 1 : -1;
} else {
return (valueA[dataProperty] > valueB[dataProperty]) ? 1 : -1;
}
};
colDef.sortBy = dataProperty; // used to display the check where appropriate on the column menu
this.gridApi.setColumnDefs(newColDefs);
}
}
EDIT: sidebar re-open filters that were open before after column defs get updated:
updateComparatorOnColDef(colId: string, dataProperty: string) {
// todo: pass in config param to tell how to compare or do logic to infer types (for misc. values, like % ranges(ex: 12% - 20%))
const openFilters = [];
const filtersToolPanel = this.gridApi.getToolPanelInstance('filters');
for(const filter of filtersToolPanel.filtersToolPanelListPanel.filterGroupComps) {
if(filter.isExpanded()) {
openFilters.push(filter.getFilterGroupId());
}
}
const newColDefs = _.cloneDeep(this.columnDefs);
const colDef = newColDefs.find(x => x.colId === colId);
if(colDef?.comparator) {
colDef.comparator = this.generateComparator(dataProperty);
colDef.sortBy = dataProperty;
this.gridApi.setColumnDefs(newColDefs);
this.gridApi.getToolPanelInstance('filters').expandFilters(openFilters);
}
}