Can flutter PaginatedDataTable rowsPerPage be set to a number not divisible by 10?
UPDATE
Data used by the FutureBuilder is fetched from a local server. At first, the list contains 3 items which results into empty DataRows being created.
My Problem
- I don't want the empty DataRows to be created
What I've Tried
- Setting the rowsPerPage count to the length of the list IF the list-length is less than the defaultRowsPerPage ELSE set it (rowsPerPage) to defaultRowsPerPage.
SAMPLE CODE
import 'package:flutter/material.dart';
import 'package:nvip/constants.dart';
import 'package:nvip/data_repo/network/centers_repo.dart';
import 'package:nvip/data_repo/tables/data_source_centers.dart';
import 'package:nvip/models/vaccination_center.dart';
class VaccinationCentersTableScreen extends StatelessWidget {
@override
Widget build(BuildContext context) => _CentersScreenBody();
}
class _CentersScreenBody extends StatefulWidget {
@override
__CentersScreenBodyState createState() => __CentersScreenBodyState();
}
class __CentersScreenBodyState extends State<_CentersScreenBody> {
int _rowsPerPage = PaginatedDataTable.defaultRowsPerPage; // This one works
int _columnIndex = 1;
bool _isSortAscending = true;
Future<List<VaccineCenter>> _centers;
CentersTableDataSource _tableDataSource;
var _scaffoldKey = GlobalKey<ScaffoldState>();
void _sort<T>(Comparable<T> getField(VaccineCenter c), int columnIndex,
bool isSortAscending) {
_tableDataSource?.sort(getField, isSortAscending);
setState(() {
_columnIndex = columnIndex;
_isSortAscending = isSortAscending;
});
}
@override
void initState() {
super.initState();
_centers = VaccineCentersDataRepo().getCenters();
}
@override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () {
Navigator.pushReplacementNamed(context, Routes.keyHome);
},
child: Scaffold(
key: _scaffoldKey,
appBar: AppBar(
title: Text("Vaccination Centers"),
centerTitle: true,
leading: IconButton(
icon: Icon(Constants.backIcon),
onPressed: () {
Navigator.pushReplacementNamed(context, Routes.keyHome);
},
),
actions: <Widget>[
IconButton(
icon: Icon(Icons.add),
tooltip: "Add vaccination center",
onPressed: () {
Navigator.pushReplacementNamed(context, Routes.keyPovAdd);
},
)
],
),
body: FutureBuilder<List<VaccineCenter>>(
future: _centers,
builder: (context, snapshot) {
if (snapshot.hasError) {
return Constants.showHasNoDataWidget(
context,
"No vaccination center(s) / place(s) of vaccinations found. "
"Press the (+) sign to add a new record.",
);
} else {
if (snapshot.hasData) {
var centerList = snapshot.data;
var centersCount = centerList.length;
var defaultRowsPerPage = PaginatedDataTable.defaultRowsPerPage;
_rowsPerPage = centersCount < defaultRowsPerPage
? centersCount
: defaultRowsPerPage;
_tableDataSource = CentersTableDataSource(centerList);
return SingleChildScrollView(
child: PaginatedDataTable(
header: Text("Places of Vaccination"),
rowsPerPage: _rowsPerPage,
onRowsPerPageChanged: (rowCount) {
setState(() {
_rowsPerPage = rowCount;
});
},
sortColumnIndex: _columnIndex,
sortAscending: _isSortAscending,
onSelectAll: (isAllChecked) =>
_tableDataSource?.selectAll(isAllChecked),
actions: <Widget>[
IconButton(
icon: Icon(Icons.add),
tooltip: "Add vaccination center",
onPressed: () {
Navigator.pushReplacementNamed(
context, Routes.keyPovAdd);
},
),
IconButton(
icon: Icon(Icons.delete_forever),
tooltip: "Delete vaccination center(s).",
onPressed: () {
Constants.showSnackBar(
_scaffoldKey, "Delete button clicked");
},
)
],
columns: <DataColumn>[
DataColumn(
label: Text("No."),
numeric: true,
onSort: (ci, isSortAscending) => _sort<num>(
(c) => centerList.indexOf(c), ci, isSortAscending),
),
DataColumn(
label: Text("Name"),
onSort: (ci, isSortAscending) =>
_sort<String>((c) => c.name, ci, isSortAscending),
),
],
source: _tableDataSource,
),
);
}
}
return Center(child: CircularProgressIndicator());
},
),
),
);
}
}
ERROR LOG
I/flutter ( 8474): ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
I/flutter ( 8474): The following assertion was thrown building FutureBuilder<List<VaccineCenter>>(dirty, state:
I/flutter ( 8474): _FutureBuilderState<List<VaccineCenter>>#92379):
I/flutter ( 8474): 'package:flutter/src/material/paginated_data_table.dart': Failed assertion: line 87 pos 19:
I/flutter ( 8474): 'availableRowsPerPage != null && availableRowsPerPage.contains(rowsPerPage)': is not true.
I/flutter ( 8474):
I/flutter ( 8474): Either the assertion indicates an error in the framework itself, or we should provide substantially
I/flutter ( 8474): more information in this error message to help you determine and fix the underlying cause.
I/flutter ( 8474): In either case, please report this assertion by filing a bug on GitHub:
I/flutter ( 8474): https://github.com/flutter/flutter/issues/new?template=BUG.md
I/flutter ( 8474):
I/flutter ( 8474): When the exception was thrown, this was the stack:
I/flutter ( 8474): #2 new PaginatedDataTable.<anonymous closure> (package:flutter/src/material/paginated_data_table.dart:87:19)
I/flutter ( 8474): #3 new PaginatedDataTable (package:flutter/src/material/paginated_data_table.dart:89:9)
I/flutter ( 8474): #4 __CentersScreenBodyState.build.<anonymous closure> (package:nvip/scenes/vaccination_centers/screen_center_table.dart:86:26)
I/flutter ( 8474): #5 _FutureBuilderState.build (package:flutter/src/widgets/async.dart)
I/flutter ( 8474): #6 StatefulElement.build (package:flutter/src/widgets/framework.dart:3809:27)
I/flutter ( 8474): #7 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3721:15)
I/flutter ( 8474): #8 Element.rebuild (package:flutter/src/widgets/framework.dart:3547:5)
I/flutter ( 8474): #9 BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2286:33)
I/flutter ( 8474): #10 _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding&PaintingBinding&SemanticsBinding&RendererBinding&WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:676:20)
I/flutter ( 8474): #11 _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding&PaintingBinding&SemanticsBinding&RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:219:5)
I/flutter ( 8474): #12 _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:990:15)
I/flutter ( 8474): #13 _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:930:9)
I/flutter ( 8474): #14 _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:842:5)
I/flutter ( 8474): #15 _invoke (dart:ui/hooks.dart:154:13)
I/flutter ( 8474): #16 _drawFrame (dart:ui/hooks.dart:143:3)
I/flutter ( 8474): (elided 2 frames from class _AssertionError)
I/flutter ( 8474): ════════════════════════════════════════════════════════════════════════════════════════════════════
UPDATE 2
My DataTableSource
import 'package:flutter/material.dart';
import 'package:nvip/models/vaccination_center.dart';
class CentersTableDataSource extends DataTableSource {
final List<VaccineCenter> _centers;
int _rowsSelectedCount = 0;
CentersTableDataSource(this._centers);
@override
DataRow getRow(int index) {
assert(index >= 0);
if (index >= _centers.length) return null;
final VaccineCenter center = _centers[index];
return DataRow.byIndex(
index: index,
selected: center.isSelected,
onSelectChanged: (selected) {
if (center.isSelected != selected) {
_rowsSelectedCount += selected ? 1 : -1;
center.isSelected = selected;
notifyListeners();
}
},
cells: <DataCell>[
DataCell(Text("${index + 1}")),
DataCell(Text(center.name)),
],
);
}
@override
bool get isRowCountApproximate => false;
@override
int get rowCount => _centers.length;
@override
int get selectedRowCount => _rowsSelectedCount;
void sort<T extends Object>(
Comparable<T> getField(VaccineCenter d), bool isAscending) {
_centers.sort((a, b) {
if (isAscending) {
final VaccineCenter c = a;
a = b;
b = c;
}
final Comparable<T> aValue = getField(a);
final Comparable<T> bValue = getField(b);
return Comparable.compare(aValue, bValue);
});
notifyListeners();
}
void selectAll(bool isAllChecked) {
_centers.forEach((center) => center.isSelected = isAllChecked);
_rowsSelectedCount = isAllChecked ? _centers.length : 0;
notifyListeners();
}
}
This error is caused by the values provided by flutter. rowsPerPage can only be 10, 20, 50 and 100.
snapshot source PaginatedDataTable
This is specified in the source PaginatedDataTable.
I'm leaving this for the next guy since I just battled this recently.
Right now, it seems like PaginatedDataTable has a couple of bugs in it... this is one of them. If the number of data elements doesn't exactly equal the selected number of rows per page, the PaginatedDataTable widget puts in 'filler rows'
Until this is fixed, I'd recommend taking the flutter PaginatedDataTable widget in the file paginated_data_table.dart and putting it in your project in order to customize it. (you'll have to replace all of the dependencies that aren't found with a simple
import 'package:flutter/material.dart';
In order to limit the number of seen rows, add the lines with // <--- below in the _getRows method seen below:
Additionally, the page count will now be off, so you'll have to change this section below in order to add the ternary operator to change the final count:
Let's say you have some method that fetches data from a remote server or locally and return a list of objects like this :
in
PaginatedDataTable
widget set :and
Hope this helps. Thanks