Closed Mayb3Nots closed 3 years ago
Hi @Mayb3Nots .
This has to be done on your end. Realize that the package doesn't even know you're using Future
s.
But I can help you with that.
Check this link. The same _activeCallbackIdentity
mechanism used there will solve your issue.
Thank you so much.
Hi @EdsonBueno Thanks for the quick response and the amazing package! After looking at the mechanism you linked and tried to implement it, it still didn't work. It seems like someone had the same issue like me https://github.com/EdsonBueno/infinite_scroll_pagination/issues/79#issuecomment-823605108. Same case as him, my widget doesn't rebuild it just updates the API parameter. And it doesn't call the fetch page function again. I wonder how he solved his issue, any advice?
pagingController.addPageRequestListener((pageKey) async {
final callBackIdentity = Object();
_activeCallbackIdentitiy = callBackIdentity;
try {
final result = await wooCommerceAPI
.get('orders?page=$pageKey&status=$customStatus')
.then((value) {
final listOfOrder = <WooOrder>[];
for (var v in value) {
listOfOrder.add(WooOrder.fromJson(v));
}
return listOfOrder;
});
final lastPage = result.length < 10;
if (callBackIdentity == _activeCallbackIdentitiy) {
if (lastPage) {
pagingController.appendLastPage(result);
} else {
final nextPageKey = pageKey + 1;
pagingController.appendPage(result, nextPageKey);
}
}
} catch (e, stackTrace) {
pagingController.error = e.toString();
handleError(e, stackTrace);
}
});
I didn't understand what you mean with "it just updates the API parameter". Can you provide me a minimal sample reproducing the issue?
So you see the customStatus
variable? When they click on a button the customStatus
changes to call a different 'status' basicll a different API call. When this happens the addPageRequestListener
doesn't get called when it is still loading the current API call. I will try to provide a minimal sample reproduction code.
Hi @Mayb3Nots . I'm sorry, but I'll have to wait for the minimal sample project. Thank you!
Sorry for late reply here is the reproduction code. If you click on refresh button when its loading it wont call _fetchPage.
import 'package:flutter/material.dart';
import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final _key = GlobalKey<ScaffoldMessengerState>();
late PagingController<int, Text> _controller;
int index = 0;
@override
void initState() {
super.initState();
_controller = PagingController(firstPageKey: 0)
..addPageRequestListener((pageKey) => _fetchPage(pageKey));
}
Future<void> _fetchPage(int pageKey) async {
WidgetsBinding.instance?.addPostFrameCallback((timeStamp) {
_key.currentState?.clearSnackBars();
_key.currentState?.showSnackBar(SnackBar(
content: Text("Refresh called"),
duration: Duration(seconds: 1),
));
});
await Future.delayed(Duration(seconds: 5));
_controller.appendLastPage([Text(pageKey.toString())]);
}
@override
Widget build(BuildContext context) {
return MaterialApp(
scaffoldMessengerKey: _key,
home: SafeArea(
child: Scaffold(
body: Column(
children: [
ElevatedButton(
child: Text('Refresh'),
onPressed: () {
index = 10;
_controller.refresh();
},
),
Expanded(
child: PagedListView(
builderDelegate: PagedChildBuilderDelegate<Text>(
itemBuilder: (context, item, index) => Center(
child: Row(
children: [item, Text(index.toString())],
),
)),
pagingController: _controller,
),
)
],
),
),
),
);
}
}
I see it now @Mayb3Nots , thank you for the sample code.
So, in you case, you can call _fetchPage
directly from your onPressed
if _controller.value.status == PagingStatus.loadingFirstPage
.
If you dont mind me asking, why not add a boolean property (eg. overrideLoadingFirstPage
) that allows override of the PagingStatus.loadingFirstPage so that it can be called and updated even when its loading?
Using your suggestion worked but it came with some challenges and extra code like making sure the previous Future doesn't complete and append the list. I would like it if this was a built-in feature. I don't mind helping to contribute if you could point me in a direction to where I can implement this.
If you dont mind me asking, why not add a boolean property (eg.
overrideLoadingFirstPage
) that allows override of the PagingStatus.loadingFirstPage so that it can be called and updated even when its loading?
I'm afraid it's not that easy, this is not how the package works. Your problem is related to your use case and how your API works, it's not related to pagination or infinite scroll. Adding more public APIs to handle that scenario would only make the package more complicated.
Thank you so much.
@Mayb3Nots Setting an error on PagingController
and then, refreshing it is working for me.
pagingController.error = "Cancelled";
pagingController.refresh();
After this, you will only need to cancel your Future
.
I am doing this using async package's CancelableOperation
.
networkOp = async.CancelableOperation.fromFuture(
yourFuture,
onCancel: () {
pagingController.error = "Cancelled";
});
Then, when refreshing,
// this will call cancel on `CancelableOperation` and set error on `PaginationController`
networkOp?.cancel();
pagingController.refresh();
@EdsonBueno do you think this solution might have any side-effects?
When you call
controller.refresh()
you have to wait till the previousaddPageRequestListener
has finished and append. How do you cancel the previous future and just refresh again?This happened to me when the user wants to switch filters quickly. So every time a filter setting is applied,
controller.refresh()
is called with the new setting. But when the refresh is called too quickly before the previous one can complete it doesn't register andaddPageRequestListener
isn't called.