feat(MatTable) Add `sortPredicate` to MatTableDataSource or MatSort
- Dominant language
- TypeScript
- Stars
- 25k
- Forks
- 6.8k
- Avg merge
- 1d 8h
- Merged PRs (30d)
- 91
Description
### Feature Description
`MatTableDataSource` already has a `filterPredicate` property that allows you to pass a function with the signature `(data: T, filter: string) => boolean` to implement a custom filtering algorithm. This makes it much easier to control the behavior of the table when passing a filter value to the data source.
The same thing is not possible when sorting: currently, the only way to control the behavior of a `MatSort` on a `MatTableDataSource` is to set its `sortingDataAccessor` property. And this is extremely limited because it only allows to control what the sorting algorithm "sees" and not how it sorts the data.
Proposition:
Add a `sortPredicate` analogous to `MatTableDataSource.filterPredicate` to either `MatTableDataSource` or `MatSort`.
This property would accept a function with the signature `(a: T, b: T, sort: Sort) => number` to mirror the signature of the comparison function passed to `Array.sort`.
An alternative would be a signature like `(sort: Sort) => (a: T, b: T) => number` which would return a comparison function derived the current sorting key/order.
Note that it would be better to be able to override the sort comparison function of only certain columns, in this case a possible solution would be to accept a function with the signature `(sort: Sort) => ((a: T, b: T) => number) | undefined` and fallback to the default comparison function on `undefined`.
This property would give a lot more control over the sorting algorithm to the user than what is currently possible.
### Use Case
There is no easy way to customize the sorting algorithm, for ex: https://stackoverflow.com/q/55016642/10061195
This property would also make it easier to sort nested objects. Currently, this needs to either give a specific name to the column to sort, or to catch the data access using `sortingDataAccessor`.
For example, a solution to the given SO question using the proposed property would be:
```ts
dataSource.sortPredicate = (sort: Sort) => {
if (sort.active === 'code') {
if (sort.direction === 'asc') {
return (a, b) => a.localeCompare(b, undefined, { numeric: true });
} else {
return (a, b) => b.localeCompare(a, undefined, { numeric: true });
}
}
};
```
or
```ts
// JS/TS does not support array as keys in object / Map
const compare = {
'code#asc': (a, b) => a.localeCompare(b, undefined, { numeric: true }),
'code#desc': (a, b) => b.localeCompare(a, undefined, { numeric: true }),
};
dataSource.sortPredicate = (sort: Sort) => compare[sort.active + '#' + sort.direction];
```
Contributor guide
Research direction
Start at MatTableDataSource and MatSort, comparing the existing filterPredicate and sortingDataAccessor behavior. Review the proposed comparator signatures and column-specific fallback before choosing an API shape. Done means custom sorting can be applied while existing default sorting remains available.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- angular, typescript
- Domain
- frontend
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100