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();
}
}