Pagination with Flutter, Ferry, Graphql?

809 views Asked by At

I have graphql hooked up, and the collection in question has about 2000 documents. What I want to do is simply load in 25 at a time. If I perform the query to fetch the full list it takes 5-10 seconds, so what I need is for it to only ask for 25 at a time. I have it working so it will load up X amount of documents and display them in a list. What I cannot figure out is how to get pagination working. Ive read the docs 100 times, but I cannot make sense of it. Here is the pagination doc for ferry https://ferrygraphql.com/docs/pagination

I am fairly new to flutter and dart so any help here would be appriecited. Thank you.

This is my code. Currently this just displays the first 25 documents and nothing else.

class DisplayPartnerOrganistions extends StatefulWidget {
  @override
  _DisplayPartnerOrganistionsState createState() =>
      _DisplayPartnerOrganistionsState();
}

class _DisplayPartnerOrganistionsState
    extends State<DisplayPartnerOrganistions> {
  var offset = 0;
  final client = GetIt.I<Client>();
  late GFetchPartnerOrganisationsReq fetchPartnerOrganisationsReq;

  @override
  void initState() {
    super.initState();
    fetchPartnerOrganisationsReq = GFetchPartnerOrganisationsReq(
      (b) => b
        ..vars.offset = offset
        ..vars.limit = 25,
    );
  }

  Widget _buildList(partners) {
    return ListView.builder(
        padding: const EdgeInsets.all(16.0),
        itemBuilder: (context, item) {
          return _buildRow(partners[item]);
        });
  }

  Widget _buildRow(partnerOrganisation) {
    return ListTile(
      title: Text(partnerOrganisation.toString()),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Partner Organisations'),
      ),
      body: Operation<GFetchPartnerOrganisationsData,
              GFetchPartnerOrganisationsVars>(
          client: client,
          operationRequest: fetchPartnerOrganisationsReq,
          builder: (context, response, error) {
            if (response!.loading) {
              return const Center(child: CircularProgressIndicator());
            }
            final partners = response.data?.partnerOrganizations;
            return _buildList(partners);
          }),
    );
  }
}

I been trying different things for about 12 hours but nothing is making any sense. Am I using the wrong widgets or something?

1

There are 1 answers

1
Valentin Vignal On

You will need to create a requestId so ferry considers the different request for the different pages the same one:

final fetchPartnerOrganisationsReq = GFetchPartnerOrganisationsReq((req) =>
  req
    ..requestId = 'myRequestId'
    ..vars.offset = 0
    ..vars.limit = 25,
);

If you don't do this, ferry creates an id from your request type and the variables of the request, which will be different for the different pages (offset won't be the same).

Then when you need to load more data, you can rebuild the request with different variables (offset). Rebuilding it will allow you to keep the same requestId you specified in the first place.

final newRequest = fetchPartnerOrganisationsReq.rebuild((request) =>
  // `requestId` is still `'myRequestId'`
  request..vars.offset = fetchPartnerOrganisationsReq.vars.offset + 25 // <- You update the offset here
  request..updateResult = (previous, result) {
    // This tells ferry what to do when you get the result from the new query.
    // Since it is using the same id as the initial one (with `offset = 0`), by default it will override the result.
    // Here we can tell ferry how to keep both.
    // `previous` is what you already received in the previous query (the previous page).
    // `result` is the new page you get.
    if (previous == null) return result; // If we didn't have a previous page yet, we just use what we got with the new query.
    return previous!.rebuild((previous) =>
      previous.partnerOrganizations.addAll(result!.partnerOrganizations), // We concatenate the lists of the previous pages and the new one.
    );
  },
);

When do you create a new request ?

It can be when you reach the end of a list. You can know that by using a ScrollController() with a listener. You can know you reached the end of the list with _scrollController.position.extentAfter == 0).