Topic: Custom sorting for datatable
mpronkbolcom premium asked 2 years ago
We use mdbootstrap datable to show an overview of vulnerabilities, and sort on severity.
Expected behavior
Ability to overide sort logic so I can sort on severity (e.g. to make it sort on severity as Critical/High/Medium/Low/Informational as descending)
Actual behavior
I cannot override the datatable sort logic (so the best result i currently have is sorting on severity as ascending - which gives Critical/High/Informational/Medium/Low )
Resources (screenshots, code snippets etc.)https://mdbootstrap.com/docs/b5/angular/data/datatables/#docsTabsAPI
Arkadiusz Idzikowski staff answered 2 years ago
You can try to disable to custom custom sorting behavior by removing [sort]="sort"
from the element with mdbTableDirective
. Then you can listen to (sortChange)
event and modify table data using your custom sorting function. Here is an example (you need to create a custom sortFn
function or completely modify onSortChange
function logic), the MdbSortChange
returns information about the active sort header and sorting direction.
HTML:
<table
class="table datatable-table"
mdbTable
mdbTableSort
#table="mdbTable"
(sortChange)="onSortChange($event)"
[dataSource]="dataSource"
[pagination]="pagination"
>
TS:
@ViewChild('table') table: MdbTableDirective<Person>;
onSortChange(event: MdbSortChange): void {
const { name, direction } = event;
if (direction !== 'none') {
this.dataSource.sort((a, b) => {
const result = this._sortFn(a[name], b[name]);
return direction === 'asc' ? result : -result;
});
}
this.dataSource = [...this.dataSource];
}
Edit:
Replaced this.table.data
with this.dataSource
in sort function to include all rows (not only rows visible in current view).
mpronkbolcom premium commented 2 years ago
hi @Arkadiusz IdzikowskiThanks! I was able to create the custom sorting logic. Unfortunately, it only sorts the rows on the current page. Instead, It should take all rows into account when ordering. Can you help a bit more ?
This is the sorting logic I have:
onSortChange(event: MdbSortChange): void {
const { name, direction } = event;
if (direction !== 'none') {
console.log(`${name} - ${direction}`);
if (name == 'severity') {
console.log('sorting on severity');
this.table.data.sort((a, b) => {
const order = [];
for (let key in Severity) {
order.push(key);
}
var textA = order.findIndex(
(key) => Severity[key as keyof typeof Severity] === a.severity
);
var textB = order.findIndex(
(key) => Severity[key as keyof typeof Severity] === b.severity
);
const result = textA < textB ? -1 : textA > textB ? 1 : 0;
return direction === 'asc' ? result : -result;
});
} else {
this.table.data.sort((a, b) => {
var textA = a[name as keyof Finding]?.toString() ?? '';
var textB = b[name as keyof Finding]?.toString() ?? '';
const result = textA < textB ? -1 : textA > textB ? 1 : 0;
return direction === 'asc' ? result : -result;
});
}
}
}
With the following table definition:
<table
class="table datatable-table"
mdbTable
mdbTableSort
#table="mdbTable"
#sortSearch="mdbTableSort"
[fixedHeader]="true"
[dataSource]="findings$ | async"
(sortChange)="onSortChange($event)"
[pagination]="paginationSearch"
[filterFn]="filterFn"
>
<thead class="datatable-header">
<tr>
<th scope="col">
<div class="form-check d-flex align-items-center mb-0">
<input
mdbCheckbox
class="datatable-header-checkbox form-check-input"
type="checkbox"
[checked]="allRowsSelected()"
(checkboxChange)="toggleAll($event)"
/>
</div>
</th>
<th
*ngFor="let header of headers"
[mdbTableSortHeader]="header"
scope="col"
>
{{ header | titlecase }}
</th>
</tr>
</thead>
Arkadiusz Idzikowski staff commented 2 years ago
@mpronkbolcom Please try to sort dataSource
(or its copy) instead of this.table.data
and make sure to update dataSource
reference so the table directive is notified about the change in data. I edited my answer and included these changes.
mpronkbolcom premium answered 2 years ago
Thanks it works, awesome!:
if (this.table.dataSource) {
if (name == 'severity') {
console.log('sorting on severity');
this.table.dataSource.sort((a, b) => {
const order = [];
for (let key in Severity) {
order.push(key);
}
var textA = order.findIndex(
(key) => Severity[key as keyof typeof Severity] === a.severity
);
var textB = order.findIndex(
(key) => Severity[key as keyof typeof Severity] === b.severity
);
const result = textA < textB ? -1 : textA > textB ? 1 : 0;
return direction === 'asc' ? result : -result;
});
} else {
this.table.dataSource.sort((a, b) => {
var textA = a[name as keyof Finding]?.toString() ?? '';
var textB = b[name as keyof Finding]?.toString() ?? '';
const result = textA < textB ? -1 : textA > textB ? 1 : 0;
return direction === 'asc' ? result : -result;
});
}
this.table.dataSource = [...this.table.dataSource];
}
}
FREE CONSULTATION
Hire our experts to build a dedicated project. We'll analyze your business requirements, for free.
Resolved
- ForumUser: Premium
- Premium support: Yes
- Technology: MDB Angular
- MDB Version: MDB5 2.0.0
- Device: any
- Browser: any
- OS: any
- Provided sample code: No
- Provided link: Yes
Arkadiusz Idzikowski staff commented 2 years ago
@mpronkbolcom Could you provide an example of a use case that you need to implement? What exactly do you need to override in the current sorting logic?
mpronkbolcom premium commented 2 years ago
hi @Arkadiusz Idzikowski, Thanks for the quick reply. I've tried to give the use case and examples above. Im creating a vulnerability dashboard using angular, and these vulnerabilities are shown in a mdbootstrap datatable. I sort the rows on severity ascending, but thats the wrong order (see expected/actual behavior). I want to implement custom sorting logic to sort it how I want.
Please let me know if this clarifies my problem
I found _sortFn here, but no documentation; https://git.mdbootstrap.com/mdb/angular/mdb5/prd/mdb5-angular-ui-kit-pro-essential/-/blob/master/table/table.directive.d.ts#L58