The table Loads Async Data in Infinite Loops

I am using Flutter 3 with Flutter Data Grid. My problem is: 

 "i Want to load asynchronous data", for which i duly followed tutorial at this page: 

Paging in Flutter DataGrid | DataPager | Syncfusion

However, when the handlePageChange is called, the asynchronous data is loaded, it again calls it, and keeps calling onRowChange without me even touching the table. 

Here is how i am implementing it :

  1. Parent Widget has initState which calls backend api to query for total rows
  2. That row count is then sent to the constructor of my custom DataSource Class which then uses the total count to check if pagination is supported or not, using the logic already being used in the "above" tutorial.
My Data Source Class: 

class ArticlesListDataSource extends DataGridSource {
List<ArticlesListType> paginatedArticlesList = [];
List<DataGridRow> dataGridRows = [];
int rowsPerPage;
final int totalLength;

ArticlesListDataSource({required this.totalLength, required this.rowsPerPage});

@override
DataGridRowAdapter? buildRow(DataGridRow row) {
return DataGridRowAdapter(
cells: row.getCells().map<Widget>((dataGridCell) {
if (dataGridCell.columnName == "cover_image") {
return Container(
padding: const EdgeInsets.all(4),
alignment: Alignment.centerLeft,
height: 90,
width: 150,
child: ProgressiveImage(
placeholder: NetworkImage("https://ik.imagekit.io/fitlive/tr:w-150,h-50,bl-6/" + dataGridCell.value.split("400x/")[1]),
thumbnail: NetworkImage("https://ik.imagekit.io/fitlive/tr:w-150,h-50/" + dataGridCell.value.split("400x/")[1]),
image: NetworkImage("https://ik.imagekit.io/fitlive/tr:w-150,h-120/" + dataGridCell.value.split("400x/")[1]),
width: 150,
fit: BoxFit.cover,
alignment: Alignment.center,
height: 90,
),
);
}
return Container(
padding: const EdgeInsets.only(
left: 30,
right: 20,
),
height: 30,
width: 30,
alignment: Alignment.centerLeft,
child: Text(
dataGridCell.value.toString(),
style: const TextStyle(
height: 1.5,
fontSize: 13,
),
),
);
}).toList());
}

@override
List<DataGridRow> get rows {
return dataGridRows;
}

@override
Future<bool> handlePageChange(int oldPageIndex, int newPageIndex) async {
List<ArticlesListType> newList = [];
int startIndex = newPageIndex > 0 ? newPageIndex * rowsPerPage : 0;
int endIndex = startIndex > 0 ? startIndex + rowsPerPage : totalLength;

if (startIndex < totalLength && endIndex <= totalLength) {
final response = await Supabase.instance.client
.from("articles")
.select(
'''
cover_image,
id,
title
''',
)
.limit(rowsPerPage)
.range(startIndex, endIndex)
.execute();

if (!response.hasError) {
if (kDebugMode) {
print(response.data);
}
response.data.forEach(
(mapped) => newList.add(
ArticlesListType(
iD: mapped['id'],
coverImage: mapped['cover_image'],
title: mapped['title'],
),
),
);
paginatedArticlesList = newList;
buildPaginatedDataGridRows();
notifyListeners();
}
} else {
paginatedArticlesList = [];
return false;
}
return true;
}

void buildPaginatedDataGridRows() {
dataGridRows = paginatedArticlesList.map<DataGridRow>((dataGridRow) {
return DataGridRow(
cells: [
DataGridCell(columnName: 'cover_image', value: dataGridRow.coverImage),
DataGridCell(columnName: 'title', value: dataGridRow.title),
],
);
}).toList(growable: false);
}
}


Parent Class (where table is created and data source constructor is called)

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

@override
State<ArticlesList> createState() => _ArticlesListState();
}

const int rowsPerPage = 15;
const double dataPagerHeight = 60.0;

class _ArticlesListState extends State<ArticlesList> {
int listLength = 0;
List<ArticlesListType>? list;
late ArticlesListDataSource articlesListDataSource;

@override
void initState() {
getData();
super.initState();
}

void getData() async {
final response = await Supabase.instance.client
.from(
"articles",
)
.select(
"id",
)
.execute(
count: CountOption.exact,
);

if (!response.hasError && response.count != null) {
setState(() {
listLength = response.count!;
articlesListDataSource = ArticlesListDataSource(
totalLength: response.count!,
rowsPerPage: rowsPerPage,
);
});
} else {
if (kDebugMode) {
print(response.error!.message);
}
}
}

@override
Widget build(BuildContext context) {
final paddingTop = MediaQuery.of(context).padding.top;
return Scaffold(
body: Container(
padding: EdgeInsets.only(top: paddingTop + 30),
height: MediaQuery.of(context).size.height,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(
height: 130,
child: Column(
children: [
Text(
"Articles Listing".toUpperCase(),
style: const TextStyle(
fontSize: 23,
fontWeight: FontWeight.w800,
),
),
const SizedBox(
height: 10,
),
const Text(
"Articles Listing in Descending Order",
style: TextStyle(
fontSize: 13,
fontWeight: FontWeight.w500,
color: Colors.grey,
),
),
const SizedBox(
height: 20,
),
ElevatedButton(
onPressed: () {
Navigator.of(context).pop();
},
style: ElevatedButton.styleFrom(
shape: const CircleBorder(),
elevation: 0,
padding: const EdgeInsets.all(12),
),
child: const Icon(
PhosphorIcons.arrowLeft,
),
),
],
),
),
listLength > 0
? FLDataTable(
dataPagerheight: dataPagerHeight,
dataSource: articlesListDataSource,
listLength: listLength,
rowsPerPage: rowsPerPage,
columns: [
GridColumn(
columnName: 'cover_image',
label: Container(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerLeft,
child: const Text(
'Article Cover',
overflow: TextOverflow.ellipsis,
),
),
),
GridColumn(
columnName: 'title',
label: Container(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
alignment: Alignment.centerLeft,
child: const Text(
'Article Title',
overflow: TextOverflow.ellipsis,
),
),
),
],
)
: Expanded(
child: Column(
children: const [
SizedBox(
height: 70,
),
Text(
"Loading Data Table",
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w800,
),
),
SizedBox(
height: 25,
),
Padding(
padding: EdgeInsets.symmetric(horizontal: 32.0),
child: SizedBox(
child: LinearProgressIndicator(),
),
),
],
),
)
],
),
),
);
}
}



8 Replies

AK Ashok Kuvaraja Syncfusion Team July 6, 2022 11:02 AM UTC

Hi Afzaal,


Unfortunately, we are not able to run your sample as we got issues with your sample. So, we prepared a new simple sample based on your requirement. In our simple sample, we could not reproduce your mentioned issue. Please refer to the below sample,

https://www.syncfusion.com/downloads/support/directtrac/general/ze/sfdatapager_sample-117547246


If possible, please modify the above simple sample to meet your requirement. It will be helpful for us to check this issue and provide you the solution at the earliest


Regards,

Ashok K



AF Afzaal July 6, 2022 01:26 PM UTC

I am doing it the same way but as you can see in my data source, i have a PRINT statement that shows how many times the handlePageChange method is called. This happens all of a sudden, NOT always. Occasionally if i tamper with a variable or change a logic.  

However, As far as i see, when it happens,  it goes into infinite loops , which means, it keeps on fetching from my API till i change Page/Route or Hard Refresh the state. Now i am not sure if this is normal in debug mode but i am unable to fix it. 



AK Ashok Kuvaraja Syncfusion Team July 7, 2022 12:41 PM UTC

Hi Afzaal,


Thanks for your update.


We suspect the infinite loops can be triggered due to the data fetching process from web API. Can you please share your working sample application to check this issue at our end? Because it will be helpful for us to debug and find the root cause as early as possible.


Regards,

Ashok K



YA Yusif Ahmadov December 20, 2022 06:39 AM UTC

Hello, i got a error like this, when i try to fetch data from backend in handlePageChange, table loads data in infinity loop



TP Tamilarasan Paranthaman Syncfusion Team December 21, 2022 01:51 PM UTC

Yusif, based on the provided information we are unable to reproduce the reported issue. It's working fine on our end. Can you please share the sample which you are facing the issue with? It will be helpful for us to check and provide the solution as soon as possible.



MQ Michael Quiblat July 5, 2023 03:45 PM UTC

Yusif were you ever able to figure this out? I'm starting to run into an infinite loop too



TB Trung Bùi March 7, 2024 02:56 AM UTC

I have the same issueImage_3979_1709780194905



TP Tamilarasan Paranthaman Syncfusion Team March 7, 2024 12:57 PM UTC

Hi Trung Bui,


Based on the provided code snippet, we are not entirely sure about the issue you are facing and the root cause. It would be more helpful for us if you could provide a sample that reproduces the issue. This will enable us to run the code and effectively diagnose the problem to provide you with a prompt solution.


However, based on our initial analysis, we suspect that the issue might be related to the implementation of the `DataGridSource.handlePageChange` method. When overriding this method, it is necessary to return either `true` or `false` to manage page changes. It's crucial not to call the super method within this override. We recommend reviewing and modifying the `DataGridSource.handlePageChange` method to directly return `true` or `false` instead of invoking the super method.


Regards,

Tamilarasan


Loader.
Up arrow icon