How to implement list pagination via signals? #226
-
I'm interested in implementing pagination for large lists using Signals. Currently, I'm unsure about the best approach to achieve this functionality with signals. Is there a recommended way to implement pagination using Signals? Any insights or suggestions on how to approach pagination with Signals would be greatly appreciated. |
Beta Was this translation helpful? Give feedback.
Replies: 6 comments 3 replies
-
I think this would be greats to show in the documentation! |
Beta Was this translation helpful? Give feedback.
-
Do you mean infinite scroll? or a paged API request using async signal? |
Beta Was this translation helpful? Give feedback.
-
I was asking for paged API request, but it would be great if I could get documentation for both. |
Beta Was this translation helpful? Give feedback.
-
Here is an example with pocketbase: import 'dart:async';
import 'package:flutter/material.dart';
import 'package:pocketbase/pocketbase.dart';
import 'package:signals/signals_flutter.dart';
class InfiniteScroll extends StatefulWidget {
const InfiniteScroll({
super.key,
required this.service,
required this.itemBuilder,
required this.filter,
});
final RecordService service;
final Widget Function(BuildContext, int, RecordModel model) itemBuilder;
final String Function(String) filter;
@override
State<InfiniteScroll> createState() => InfiniteScrollState();
}
class InfiniteScrollState extends State<InfiniteScroll> {
final scrollController = ScrollController();
final currentPage = signal(0);
final totalPages = signal(1);
final loading = signal(false);
final hasMore = signal(true);
final items = listSignal<RecordModel>([]);
final search = TextEditingController();
@override
void initState() {
super.initState();
scrollController.addListener(() {
if (scrollController.position.pixels >=
scrollController.position.maxScrollExtent) {
fetchPage();
}
});
fetchPage();
}
Future<void> startSearch() async {
currentPage.value = 0;
totalPages.value = 1;
hasMore.value = true;
items.clear();
await fetchPage();
}
Future<void> fetchPage() async {
if (loading.value) return;
loading.value = true;
final page = currentPage.value + 1;
final q = search.text.trim();
if (page <= totalPages.value) {
try {
final list = await widget.service.getList(
page: page,
filter: q.isEmpty ? null : widget.filter(q),
);
currentPage.value = page;
totalPages.value = list.totalPages;
hasMore.value = page < list.totalPages;
items.addAll(list.items);
// scrollController.jumpTo(scrollController.position.maxScrollExtent);
} catch (e) {
debugPrint('error fetching page: $e');
}
}
loading.value = false;
}
@override
Widget build(BuildContext context) {
return Watch((context) {
return CustomScrollView(
controller: scrollController,
slivers: [
SliverToBoxAdapter(
child: Padding(
padding: const EdgeInsets.all(20),
child: TextField(
controller: search,
decoration: InputDecoration(
labelText: 'Search',
border: const OutlineInputBorder(),
prefixIcon: InkWell(
onTap: startSearch,
child: const Icon(Icons.search),
),
),
onEditingComplete: startSearch,
),
),
),
if (items.isEmpty)
const SliverFillRemaining(
child: Center(child: CircularProgressIndicator()),
)
else
SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) {
if (items().isEmpty) {
return const Center(child: Text('No results found'));
}
if (index == items().length && hasMore.value) {
return const Center(child: CircularProgressIndicator());
}
return widget.itemBuilder(
context,
index,
items.value[index],
);
},
childCount: items.value.length + (hasMore.value ? 1 : 0),
),
),
],
);
});
}
} |
Beta Was this translation helpful? Give feedback.
-
Hi @rodydavis , i have one question to understand signals better, a bit unrelated to infinite scroll discussion here. |
Beta Was this translation helpful? Give feedback.
Here is an example with pocketbase: