I have a datatable in Flutter which display data from a Firebase database. It includes two columns namely 'Registration Date' and 'Expiry Date' which I was to sort when the user taps on the respective columns. Moreover, I have used DateFormat('dd-MM-yyyy') to format the dates, so those are stored as strings in my database.
This is one such entry in my database and this is how the columns look in the DataTable.
import 'dart:math';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_database/firebase_database.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:sub_mgmt/page/addnewpage.dart';
import 'package:sub_mgmt/page/data/users.dart';
import 'package:sub_mgmt/page/model/user.dart';
import 'editpage.dart';
class MemberList extends StatefulWidget {
const MemberList({Key? key}) : super(key: key);
@override
State<MemberList> createState() => MemberListState();
}
class MemberListState extends State<MemberList> {
static int counter = 1;
// Reading data from firebase
CollectionReference _referenceMembers =
FirebaseFirestore.instance.collection('users');
late Stream<QuerySnapshot> _streamMembers;
List<int> selectedIndex = [];
List<String> selectedDocID = [];
final searchController = TextEditingController();
@override
void initState() {
super.initState();
_streamMembers = _referenceMembers.snapshots();
}
int? sortColumnIndex;
bool isAscending = false;
@override
Widget build(BuildContext context) {
return Scaffold(
body: StreamBuilder<QuerySnapshot>(
stream: _streamMembers,
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasError) {
return Center(child: Text(snapshot.error.toString()));
}
if (snapshot.connectionState == ConnectionState.active) {
QuerySnapshot querySnapshot = snapshot.data;
List<QueryDocumentSnapshot> listQueryDocumentSnapshot =
querySnapshot.docs;
counter = 0;
return ScrollableWidget(
child: Column(
children: [
DataTable(
sortAscending: isAscending,
sortColumnIndex: sortColumnIndex,
columns: [
DataColumn(
label: Text(
'Sr',
style: TextStyle(fontWeight: FontWeight.bold),
),
),
DataColumn(
label: Text(
'Name',
style: TextStyle(fontWeight: FontWeight.bold),
),
),
DataColumn(
label: Text(
'Phone',
style: TextStyle(fontWeight: FontWeight.bold),
),
),
DataColumn(
label: Text(
'Plan',
style: TextStyle(fontWeight: FontWeight.bold),
),
),
DataColumn(
label: Text(
'Fee Paid',
style: TextStyle(fontWeight: FontWeight.bold),
),
),
DataColumn(
label: Text(
'Reg. Date',
style: TextStyle(fontWeight: FontWeight.bold),
),
onSort: onSort,
),
DataColumn(
label: Text(
'Expiry Date',
style: TextStyle(fontWeight: FontWeight.bold),
),
onSort: onSort,
),
DataColumn(
label: Text(
'',
style: TextStyle(fontWeight: FontWeight.bold),
),
),
],
rows: listQueryDocumentSnapshot
.map((element) => DataRow(
selected: selectedDocID.contains(element.id),
onSelectChanged: (isSelected) => setState(() {
final isAdding =
isSelected != null && isSelected;
if (isAdding) {
selectedDocID.add(element.id);
} else {
selectedDocID.remove(element.id);
}
}),
cells: <DataCell>[
DataCell(Text((++counter).toString())),
DataCell(Text(element['Name'])),
DataCell(Text(element['Phone'].toString())),
DataCell(Text(element['Plan'].toString())),
DataCell(
Text(element['Fee Paid'].toString())),
DataCell(Text(element['Registration Date'])),
DataCell(Text(element['Expiry Date'])),
DataCell(IconButton(
splashRadius: 22,
color: Colors.black38,
icon: Icon(Icons.edit),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => EditPage(
element.id,
element['Name'],
element['Phone'],
element['Plan'],
element['Fee Paid'],
element['Registration Date']),
),
);
},
))
],
))
.toList(),
columnSpacing: 32,
),
SizedBox(height: 80),
],
),
);
}
return Center(child: CircularProgressIndicator());
}),
floatingActionButtonLocation: FloatingActionButtonLocation.endDocked,
floatingActionButton: Padding(
padding: const EdgeInsets.all(18.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: FloatingActionButton(
onPressed: () {
if (selectedDocID.isNotEmpty) {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text("Delete"),
content: Text("Delete Data?"),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15)),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text("No")),
TextButton(
onPressed: () {
for (var i in selectedDocID) {
final docUser = FirebaseFirestore.instance
.collection('users')
.doc(i);
docUser.delete();
}
Navigator.of(context).pop();
},
child: Text("Yes"))
],
);
});
}
},
tooltip: 'Delete',
elevation: 4.0,
child: Icon(Icons.delete),
),
),
FloatingActionButton(
onPressed: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) => AddNewPage()));
},
tooltip: 'Add',
elevation: 4.0,
child: Icon(Icons.add),
)
],
),
),
);
}
void onSort(int columnIndex, bool ascending) async {
setState(() {
this.sortColumnIndex = columnIndex;
this.isAscending = ascending;
});
}
}
class ScrollableWidget extends StatelessWidget {
final Widget child;
const ScrollableWidget({
Key? key,
required this.child,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return SingleChildScrollView(
physics: BouncingScrollPhysics(),
scrollDirection: Axis.horizontal,
child: SingleChildScrollView(
physics: BouncingScrollPhysics(),
scrollDirection: Axis.vertical,
child: child,
),
);
}
}
I understand that I need to use the onSort
property of DataColumn, but I'm facing difficulty in implementing it. Any help would be appreciated.