houba
houba

Reputation: 536

Sorting Column Values in Flutter DataTable

I am having serious difficulty in sorting columns in my DataTable.

Here is my code

  SingleChildScrollView(
  scrollDirection: Axis.horizontal,
  child: DataTable(
    sortColumnIndex: 0,
    sortAscending: true,

    columnSpacing: 5.0,
      horizontalMargin: 10,
    columns: [
      DataColumn(label: Text('Col1'),          
      DataColumn(label: Text('Col2'),numeric: false ),
      DataColumn(label: Text('Col3'),numeric: true ),
      DataColumn(label: Text('Col4'), numeric: true),
      DataColumn(label: Text('Col5'), numeric: true),
    ],
    rows: myList
        .map(
        ((element) => DataRow(
          cells: <DataCell>[
            DataCell(Text(element["Col1"]), placeholder: true,showEditIcon: false),
            DataCell(Text(element["Col2"].toString())),
            DataCell(Text(element["Col3"].toString())),
            DataCell(Text(element["Col4"].toString())),
            DataCell(Text(element["Col5"].toString())),
          ],
        )),
    ).toList(),
  ),
));

What more am I meant to do? Ideally, I'd like to have the sort function on whichever column the user presses on, but for now, I'd be delighted with just 1 column working being sortable.

As you can see, I have added the constraints:

    sortColumnIndex: 0,
    sortAscending: true,

But all I get is an arrow near 1st column (ColumnIndex = 0) - which really does nothing when you press it.

What am I doing wrong?

Upvotes: 5

Views: 7327

Answers (2)

Kanagavelu Sugumar
Kanagavelu Sugumar

Reputation: 19270

  1. The DataTable should be part of StatefulWidget
  2. The StatefulWidget is needed re-render the widget whenever the sort is required on different column
  3. To trigger re-render build(BuildContext context) method, we should add setState(() {} method inside the onSort: (columnIndex, ascending) {} like below
            DataColumn(
              label: const Text(
                'Name',
                style: TextStyle(fontStyle: FontStyle.italic),
              ),
              onSort: (columnIndex, ascending) {
                print("columnIndex:$columnIndex");
                print("ascending:$ascending");
                setState(() {
                  sortColumnIndex = columnIndex;
                  isAscending = ascending;
                });
  1. onSort: (columnIndex, ascending) {} will be called every time the column header is clicked.

  2. DataTable should have state variable e.g. sortColumnIndex, so that every sorting click on different column will reset this index, and corresponding index column will get arrow Icon.

        child: DataTable(
          border: TableBorder.symmetric(),
          sortAscending: isAscending,
          sortColumnIndex: sortColumnIndex,
  1. isAscending will be used to revert the arrow, if the same column pressed again.

  2. Similar to sortColumnIndex state variable; we have to sort the table data manually so that new sorted values will be rendered after the click.


class MyStatefulWidget extends StatefulWidget {
  const MyStatefulWidget({Key? key}) : super(key: key);

  @override
  State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
}

class _MyStatefulWidgetState extends State<MyStatefulWidget> {
  var isAscending = true;
  var sortColumnIndex = 0;

  @override
  Widget build(BuildContext context) {

    return Scaffold(
      body: SingleChildScrollView(
        scrollDirection: Axis.vertical,
        child: DataTable(
          border: TableBorder.symmetric(),
          sortAscending: isAscending,
          sortColumnIndex: sortColumnIndex,
          columns: <DataColumn>[
            DataColumn(
              label: const Text(
                'Name',
                style: TextStyle(fontStyle: FontStyle.italic),
              ),
              onSort: (columnIndex, ascending) {
                print("columnIndex:$columnIndex");
                print("ascending:$ascending");
                setState(() {
                  sortColumnIndex = columnIndex;
                  isAscending = ascending;
                });
              },
            ),
            DataColumn(
              label: const Text(
                'Age',
                style: TextStyle(fontStyle: FontStyle.italic),
              ),
              onSort: (columnIndex, ascending) {
                print("columnIndex:$columnIndex");
                print("ascending:$ascending");
                setState(() {
                  sortColumnIndex = columnIndex;
                  isAscending = ascending;
                });
              },
            ),
            DataColumn(
              label: const Text(
                'Role',
                style: TextStyle(fontStyle: FontStyle.italic),
              ),
              onSort: (columnIndex, ascending) {
                print("columnIndex:$columnIndex");
                print("ascending:$ascending");
                setState(() {
                  sortColumnIndex = columnIndex;
                  isAscending = ascending;
                });
              },
            ),
          ],
          rows: const <DataRow>[
            DataRow(
              cells: <DataCell>[
                DataCell(Text('Sarah')),
                DataCell(Text('19')),
                DataCell(Text('Student')),
              ],
            ),
            DataRow(
              cells: <DataCell>[
                DataCell(Text('Janine')),
                DataCell(Text('43')),
                DataCell(Text('Professor')),
              ],
            ),
            DataRow(
              cells: <DataCell>[
                DataCell(Text('William')),
                DataCell(Text('27')),
                DataCell(Text('Associate Professor')),
              ],
            ),
          ],
        ),
      ),
    );
  }
}

Upvotes: 2

Elin
Elin

Reputation: 133

You have to add an onSort property to the column that will be sorted, and call a sorting function.

bool sort = true; // or `false`...

DataTable(
  sortAscending: sort,
  sortColumnIndex: 0,
  columns: [
    DataColumn(
      label: Text("Col1"),
      onSort: (columnIndex, ascending) {
        setState(() {
          sort = !sort;
        });

        onSortColum(columnIndex, ascending);
      }),
      ...

And the onSortColum function:

onSortColum(int columnIndex, bool ascending) {
  if (columnIndex == 0) {
    if (ascending) {
      yourDataList.sort((a, b) => a['name'].compareTo(b['name']));
    } else {
      yourDataList.sort((a, b) => b['name'].compareTo(a['name']));
    }
  }
}

Upvotes: 11

Related Questions