Sorting in Flutter Datagrid (SfDataGrid)
6 Apr 202224 minutes to read
The datagrid provides the built-in support to sort one or more columns by setting the SfDataGrid.allowSorting property to true. When sorting is applied, the datagrid automatically rearranges the data to match with the current sort criteria. When SfDataGrid.allowSorting
is true, you can sort the data simply by tapping the column header. Once sorting is applied, the datagrid shows a sort icon in the respective column header indicating the sort direction.
Programmatic sorting
The datagrid provides support to sort the columns programmatically. You can manually define the SortColumnDetails objects, and add it in the SfDataGrid.source.sortedColumns collection. The datagrid sorts the data based on the SortColumnDetails
objects added to this collection. If you want to perform sorting at run time, you should call SfDataGrid.source.sort() method after adding the SortColumnDetails
to the SfDataGrid.source.sortedColumns
collection.
The SortColumnDetails
object holds the following two properties:
- name : Name of the column to be sorted.
- sortDirection : Specifies the ascending or descending direction.
import 'package:syncfusion_flutter_datagrid/datagrid.dart';
late EmployeeDataSource _employeeDataSource;
List<Employee> _employees = <Employee>[];
@override
void initState() {
super.initState();
_employees = getEmployeeData();
_employeeDataSource = EmployeeDataSource(employees: _employees);
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(mainAxisAlignment: MainAxisAlignment.center, children: [
SfDataGrid(source: _employeeDataSource, columns: [
GridColumn(
columnName: 'id',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerRight,
child: Text(
'ID',
overflow: TextOverflow.ellipsis,
))),
GridColumn(
columnName: 'name',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerLeft,
child: Text(
'Name',
overflow: TextOverflow.ellipsis,
))),
GridColumn(
columnName: 'city',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerLeft,
child: Text(
'City',
overflow: TextOverflow.ellipsis,
))),
GridColumn(
columnName: 'freight',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerRight,
child: Text(
'Freight',
overflow: TextOverflow.ellipsis,
))),
]),
Padding(
padding: EdgeInsets.symmetric(horizontal: 16.0),
child: TextButton(
onPressed: () {
_employeeDataSource.sortedColumns.add(SortColumnDetails(
name: 'name', sortDirection: DataGridSortDirection.ascending));
_employeeDataSource.sort();
},
child: Text('Apply sort')),
)
]));
}
Multi-column sorting
The datagrid sorts the data against more than one columns by setting the SfDataGrid.allowMultiColumnSorting property to true. The number of columns by which the data can be sorted is unlimited. To apply sorting for multiple columns, tap the desired column headers after setting the SfDataGrid.allowMultiColumnSorting
property.
To apply sorting for multiple columns in web and desktop, you can click the column header by pressing the Ctrl key.
import 'package:syncfusion_flutter_datagrid/datagrid.dart';
@override
Widget build(BuildContext context) {
return Scaffold(
body: SfDataGrid(
source: _employeeDataSource,
allowSorting: true,
allowMultiColumnSorting: true,
columns: [
GridColumn(
columnName: 'id',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerRight,
child: Text(
'ID',
overflow: TextOverflow.ellipsis,
))),
GridColumn(
columnName: 'name',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerLeft,
child: Text(
'Name',
overflow: TextOverflow.ellipsis,
))),
GridColumn(
columnName: 'city',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerLeft,
child: Text(
'City',
overflow: TextOverflow.ellipsis,
))),
GridColumn(
columnName: 'freight',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerRight,
child: Text(
'Freight',
overflow: TextOverflow.ellipsis,
))),
],
));
}
Tri-state sorting
In addition to sort the data in ascending/descending order, the SfDataGrid unsort the data in the original order by clicking the header again after sorting to descending order by setting the SfDataGrid.allowTriStateSorting property to true. When this property is set, sorting in each column iterates through three sort states: ascending, descending, and unsort.
import 'package:syncfusion_flutter_datagrid/datagrid.dart';
@override
Widget build(BuildContext context) {
return Scaffold(
body: SfDataGrid(
source: _employeeDataSource,
allowSorting: true,
allowMultiColumnSorting: true,
allowTriStateSorting: true,
columns: [
GridColumn(
columnName: 'id',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerRight,
child: Text(
'ID',
overflow: TextOverflow.ellipsis,
))),
GridColumn(
columnName: 'name',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerLeft,
child: Text(
'Name',
overflow: TextOverflow.ellipsis,
))),
GridColumn(
columnName: 'city',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerLeft,
child: Text(
'City',
overflow: TextOverflow.ellipsis,
))),
GridColumn(
columnName: 'freight',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerRight,
child: Text(
'Freight',
overflow: TextOverflow.ellipsis,
))),
],
));
}
Sort column in double tap
By default, column gets sorted when column header clicked. This behavior can be changed to sort the column in double click action by setting SfDataGrid.sortingGestureType property to doubleTap
.
import 'package:syncfusion_flutter_datagrid/datagrid.dart';
@override
Widget build(BuildContext context) {
return Scaffold(
body: SfDataGrid(
source: _employeeDataSource,
allowSorting: true,
sortingGestureType: SortingGestureType.doubleTap,
columns: [
GridColumn(
columnName: 'id',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerRight,
child: Text(
'ID',
overflow: TextOverflow.ellipsis,
))),
GridColumn(
columnName: 'name',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerLeft,
child: Text(
'Name',
overflow: TextOverflow.ellipsis,
))),
GridColumn(
columnName: 'city',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerLeft,
child: Text(
'City',
overflow: TextOverflow.ellipsis,
))),
GridColumn(
columnName: 'freight',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerRight,
child: Text(
'Freight',
overflow: TextOverflow.ellipsis,
))),
],
));
}
Show sort number
The datagrid provides support the sequence numbers to display the sorted columns during multi-column sorting by setting SfDataGrid.showSortNumbers is set to true. This is applicable when the SfDataGrid.allowMultiColumnSorting
property is enabled.
import 'package:syncfusion_flutter_datagrid/datagrid.dart';
@override
Widget build(BuildContext context) {
return Scaffold(
body: SfDataGrid(
source: _employeeDataSource,
allowSorting: true,
allowMultiColumnSorting: true,
showSortNumbers: true,
columns: [
GridColumn(
columnName: 'id',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerRight,
child: Text(
'ID',
overflow: TextOverflow.ellipsis,
))),
GridColumn(
columnName: 'name',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerLeft,
child: Text(
'Name',
overflow: TextOverflow.ellipsis,
))),
GridColumn(
columnName: 'city',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerLeft,
child: Text(
'City',
overflow: TextOverflow.ellipsis,
))),
GridColumn(
columnName: 'freight',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerRight,
child: Text(
'Freight',
overflow: TextOverflow.ellipsis,
))),
],
));
}
Disable sorting for an individual column
The data grid disables sorting for an individual column by setting the GridColumn.allowSorting property to false. The default value of this property is true. So all the columns in the SfDataGrid.columns collection can be sorted when SfDataGrid.allowSorting
is set to true.
import 'package:syncfusion_flutter_datagrid/datagrid.dart';
@override
Widget build(BuildContext context) {
return Scaffold(
body: SfDataGrid(
source: _employeeDataSource,
allowSorting: true,
columns: [
GridColumn(
columnName: 'id',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerRight,
child: Text(
'ID',
overflow: TextOverflow.ellipsis,
))),
GridColumn(
columnName: 'name',
allowSorting: false,
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerLeft,
child: Text(
'Name',
overflow: TextOverflow.ellipsis,
))),
GridColumn(
columnName: 'city',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerLeft,
child: Text(
'City',
overflow: TextOverflow.ellipsis,
))),
GridColumn(
columnName: 'freight',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerRight,
child: Text(
'Freight',
overflow: TextOverflow.ellipsis,
))),
],
));
}
Change the color of sort icon
The color of sort icon can be customized by using SfDataGridThemeData.sortIconColor.
The following code describes how to change sort icon color by using SfDataGridTheme.
import 'package:syncfusion_flutter_datagrid/datagrid.dart';
import 'package:syncfusion_flutter_core/theme.dart';
@override
Widget build(BuildContext context) {
return Scaffold(
body: SfDataGridTheme(
data: SfDataGridThemeData(sortIconColor: Colors.redAccent),
child: SfDataGrid(
source: _employeeDataSource,
allowSorting: true,
allowMultiColumnSorting: true,
columns: [
GridColumn(
columnName: 'id',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerRight,
child: Text(
'ID',
overflow: TextOverflow.ellipsis,
))),
GridColumn(
columnName: 'name',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerLeft,
child: Text(
'Name',
overflow: TextOverflow.ellipsis,
))),
GridColumn(
columnName: 'city',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerLeft,
child: Text(
'City',
overflow: TextOverflow.ellipsis,
))),
GridColumn(
columnName: 'freight',
label: Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerRight,
child: Text(
'Freight',
overflow: TextOverflow.ellipsis,
))),
],
),
));
}
Set a custom sorting icon
SfDataGrid
allows you to change the sort icon by using the SfDataGridThemeData.sortIcon property. The DataGrid should be wrapped inside the SfDataGridTheme
.
The SfDataGridThemeData
and SfDataGridTheme
classes are available in syncfusion_flutter_core package. So, import the following file.
import 'package:syncfusion_flutter_core/theme.dart';
import 'package:syncfusion_flutter_core/theme.dart';
import 'package:syncfusion_flutter_datagrid/datagrid.dart';
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: const BackButton(),
title: const Text('Syncfusion Flutter DataGrid'),
),
body: SfDataGridTheme(
data:
SfDataGridThemeData(sortIcon: const Icon(Icons.arrow_circle_up)),
child: SfDataGrid(
source: _employeeDataSource,
allowSorting: true,
selectionMode: SelectionMode.multiple,
navigationMode: GridNavigationMode.cell,
columnWidthMode: ColumnWidthMode.fill,
columns: [
GridColumn(
columnName: 'id',
label: Container(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.center,
child: const Text(
'ID',
overflow: TextOverflow.ellipsis,
))),
GridColumn(
columnName: 'name',
label: Container(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.center,
child: const Text(
'Name',
overflow: TextOverflow.ellipsis,
))),
GridColumn(
columnName: 'designation',
label: Container(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.center,
child: const Text(
'Designation',
overflow: TextOverflow.ellipsis,
))),
GridColumn(
columnName: 'salary',
label: Container(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.center,
child: const Text(
'Salary',
overflow: TextOverflow.ellipsis,
))),
]),
));
}
Custom sorting
The datagrid allows to sort columns based on custom logic. For each column, you can provide different sorting criteria by overriding the following methods from DataGridSource,
- performSorting : Called when the sorting is applied to the column. Overriding this method gives complete control over sorting. You can handle the sorting completely in your own way.
- compare : You can override this method to compare two objects and return the sorting order based on the criteria.
Sort column based on string length
The following code shows how to perform custom sorting for the columns based on the string length by overriding the compare
method.
import 'package:syncfusion_flutter_datagrid/datagrid.dart';
class EmployeeDataSource extends DataGridSource {
EmployeeDataSource({required List<Employee> employees}) {
dataGridRows = employees
.map<DataGridRow>((dataGridRow) => DataGridRow(cells: [
DataGridCell<int>(columnName: 'id', value: dataGridRow.id),
DataGridCell<String>(columnName: 'name', value: dataGridRow.name),
DataGridCell<String>(
columnName: 'designation', value: dataGridRow.designation),
DataGridCell<int>(columnName: 'salary', value: dataGridRow.salary)
]))
.toList();
}
List<DataGridRow> dataGridRows = [];
@override
List<DataGridRow> get rows => dataGridRows;
@override
DataGridRowAdapter? buildRow(DataGridRow row) {
return DataGridRowAdapter(
cells: row.getCells().map<Widget>((dataGridCell) {
return Container(
alignment: (dataGridCell.columnName == 'id' ||
dataGridCell.columnName == 'salary')
? Alignment.centerRight
: Alignment.centerLeft,
padding: EdgeInsets.symmetric(horizontal: 16.0),
child: Text(
dataGridCell.value.toString(),
overflow: TextOverflow.ellipsis,
));
}).toList());
}
@override
int compare(DataGridRow? a, DataGridRow? b, SortColumnDetails sortColumn) {
final String? value1 = a
?.getCells()
.firstWhereOrNull((element) => element.columnName == sortColumn.name)
?.value;
final String? value2 = b
?.getCells()
.firstWhereOrNull((element) => element.columnName == sortColumn.name)
?.value;
int? aLength = value1?.length;
int? bLength = value2?.length;
if (aLength == null || bLength == null) {
return 0;
}
if (aLength.compareTo(bLength) > 0) {
return sortColumn.sortDirection == DataGridSortDirection.ascending
? 1
: -1;
} else if (aLength.compareTo(bLength) == -1) {
return sortColumn.sortDirection == DataGridSortDirection.ascending
? -1
: 1;
} else {
return 0;
}
}
}
NOTE
Download demo application from GitHub.
Case-insensitive sorting
The following code shows how to perform custom sorting for the columns based on the case-insensitive by overriding the compare
method.
import 'package:syncfusion_flutter_datagrid/datagrid.dart';
class EmployeeDataSource extends DataGridSource {
EmployeeDataSource({required List<Employee> employees}) {
dataGridRows = employees
.map<DataGridRow>((dataGridRow) => DataGridRow(cells: [
DataGridCell<int>(columnName: 'id', value: dataGridRow.id),
DataGridCell<String>(columnName: 'name', value: dataGridRow.name),
DataGridCell<String>(
columnName: 'designation', value: dataGridRow.designation),
DataGridCell<int>(columnName: 'salary', value: dataGridRow.salary)
]))
.toList();
}
List<DataGridRow> dataGridRows = [];
@override
List<DataGridRow> get rows => dataGridRows;
@override
DataGridRowAdapter? buildRow(DataGridRow row) {
return DataGridRowAdapter(
cells: row.getCells().map<Widget>((dataGridCell) {
return Container(
alignment: (dataGridCell.columnName == 'id' ||
dataGridCell.columnName == 'salary')
? Alignment.centerRight
: Alignment.centerLeft,
padding: EdgeInsets.symmetric(horizontal: 16.0),
child: Text(
dataGridCell.value.toString(),
overflow: TextOverflow.ellipsis,
));
}).toList());
}
@override
int compare(DataGridRow? a, DataGridRow? b, SortColumnDetails sortColumn) {
if (sortColumn.name == 'name') {
final String? value1 = a
?.getCells()
.firstWhereOrNull((element) => element.columnName == sortColumn.name)
?.value
.toString();
final String? value2 = b
?.getCells()
.firstWhereOrNull((element) => element.columnName == sortColumn.name)
?.value
.toString();
if (value1 == null || value2 == null) {
return 0;
}
if (sortColumn.sortDirection == DataGridSortDirection.ascending) {
return value1.toLowerCase().compareTo(value2.toLowerCase());
} else {
return value2.toLowerCase().compareTo(value1.toLowerCase());
}
}
return super.compare(a, b, sortColumn);
}
}
NOTE
Download demo application from GitHub.