0

I have a firestore collection for 'brews' . Cant find a way to paginate the list of Brews. you can find the whole code at (https://github.com/iamshaunjp/flutter-firebase/tree/lesson-27) if needed. Thanks..

class BrewList extends StatefulWidget {
  @override
  _BrewListState createState() => _BrewListState();
}

class _BrewListState extends State<BrewList> {
  @override
  Widget build(BuildContext context) {

    final brews = Provider.of<List<Brew>>(context) ?? [];

    return ListView.builder(
      itemCount: brews.length,
      itemBuilder: (context, index) {
        return BrewTile(brew: brews[index]);
      },
    );
  }
}
alex
  • 130
  • 2
  • 12
  • Hi, can you clarify what exactly you would like help with. Would you like to know how to navigate screens? – wcyankees424 Apr 07 '20 at 06:49
  • hello.. i want the ui to load more brews as the user scrolls ..currently with this code it loads all the brews that are there in the firestore collection 'brews' – alex Apr 07 '20 at 06:53
  • I just want to make sure I understand so you want instead of a scrollable list you want a certain number of 'brews' per tab lets say. – wcyankees424 Apr 07 '20 at 07:15
  • i want to load initially '20' brews and as the user scrolls to the end of this list of '20' brews...it should load more '10' more brews and as the user scrolls to the end of this list..10 more and so on..as long as there are more brews in the firestore collection.. i hope this is clear.. – alex Apr 07 '20 at 07:23
  • yes i got it now sorry for the confusion if no one else answers you ill have one for you in the morning its 3am here :) – wcyankees424 Apr 07 '20 at 07:54
  • no problem..thank you so much for responding.. – alex Apr 07 '20 at 07:56
  • Okay this actually proved to be a lot harder than I thought it was going to be I have it most of the way there the problem is when it loads the next brews I haven't gotten it to be able to start from the location it left off I am working on it still – wcyankees424 Apr 07 '20 at 20:08
  • that explains why nobody else has yet..but its better than loading all the brews ..while you are working at it.. please share the changes that you made to the code.. – alex Apr 08 '20 at 01:26
  • Ill post what I have so far and you can tell me if thats what you you wanted because to be honest I am alittle confused why you dont want to just load them all at once. As to why people aren't answering you it is more to do with the fact that you haven't attempted the issue yourself and are asking for someone to solve an issue from scratch. That is most likely why your question got downgraded. I don't mind I like challenges its the fun of coding right :) – wcyankees424 Apr 08 '20 at 01:35
  • yes please go ahead..post it..and also..the fact is i attempted the issue myself and turned out to be a little tough.. – alex Apr 08 '20 at 01:55
  • i dont want to load them all at once because if there are 100 or 200 brews or more..it would load unnecessarily on the app when the chances are that the user won't scroll so far..and also firestore will charge for that. – alex Apr 08 '20 at 02:02
  • how are your brews stored in firebase ex: all in array, each in their own field, each in own document – wcyankees424 Apr 08 '20 at 02:17
  • i have a collection of brews and that has a uid for all the brews and each brew has 3 different fields.. there's a git repo for the whole code to the app ..you can check it out ..its link (https://github.com/iamshaunjp/flutter-firebase/tree/lesson-27) – alex Apr 08 '20 at 02:30

2 Answers2

1

Okay sorry about delay in answer but this is what i think your function would look like this saves all your brews into a list as brews then you could map them to widgets.

Future<void> queryFirebase(String starting, String ending) async {
    final List<Brew> brewsList = [];  //this need to be intialized higher up not in this function
    //if you intialized it in this function it will reset to empty every time you call the function

    QuerySnapshot brewsSnapshot = await Firestore.instance
        .collection('collection')
        .where('name', isGreaterThanOrEqualTo: starting)
        .where('name', isLessThanOrEqualTo: ending)
        .orderBy('name')//this sorts your query if you want that
        .getDocuments();

    if (brewsSnapshot == null) {
      return;
    }

    brewsSnapshot.documents.forEach(
      (DocumentSnapshot brewsDocuments) => {
        brewsList.add(
          Brew(
            sugars: brewsDocuments.data['sugars'],
            name: brewsDocuments.data['name'],
            strength: int.parse(
              brewsDocuments.data['sugars'],
            ),
          ),
        ),
      },
    );
    notifyListeners();
  }

then the calls to the function would be something like


await queryFirebase('A', //name of last brew you want displayed initially)
await queryFirebase('//next brew after last one from last function', //name of last brew you want displayed )
await queryFirebase('//next brew after last one from last function', 'Z' )


wcyankees424
  • 2,554
  • 2
  • 12
  • 24
  • I'm not sorting it with name..added a timestamp to each brew..i'm trying this out..thanks again – alex Apr 10 '20 at 06:38
  • Oh thats right but all you have to do is where it says 'name' put in 'timestamp' or whatever your calling it and then insteand of 'A' you would put a time you know is before any entry went into the database – wcyankees424 Apr 10 '20 at 06:56
  • hmmm. using timestamp idk if you will be able to get exactly 20 then 10 then 10 though cause you would have to know the timestamps prior to querying if you do then you would just plug then in in place of the names of the brews – wcyankees424 Apr 10 '20 at 06:58
  • click the up arrow or accept button on some of my posts so i can get some points for helping you. I will continue to help you just a little payment lol :) – wcyankees424 Apr 10 '20 at 07:01
  • you think using the names is more reliable than using the timestamp? – alex Apr 10 '20 at 07:01
  • I don't see a way you would know you time stamp before hand without querying which defeats the purpose – wcyankees424 Apr 10 '20 at 14:28
  • link the question – wcyankees424 Apr 13 '20 at 15:36
  • okay...this was really helpful finally..with some modifications..I got it working ..I used startAfter() instead of where()..there is a slight problem though..it loads the next data on the first scroll..but keeps fetching the same data(the data that is fetched on the first scroll down) . on every scroll .. if you have any solution. the question is still open..if not.. Thank you for your help so far. – alex Apr 24 '20 at 17:24
0

Okay so I want to explain a little about whats going on here first 20 items load then NotificationListener triggers every time we reach the bottom of the list until all the items are loaded then it turns off. Every time it triggers it adds ten items to itemCount. Now I have some parts in here just for demonstration the Future that that waits 3 seconds you probably wouldn't use but since I just used a list of numbers if I didn't do that there would be no loading time. For you grabbing from firebase there probably will be.

 final ScrollController _controller = ScrollController();


  int scrollPosition = 1;
  int itemCount = 20;
  bool isLoading = false;

  List<int> numbers = [//bunch of numbers];

  void _onEndScroll(ScrollMetrics metrics) {
    if (metrics.pixels == metrics.maxScrollExtent) {
      setState(() {
        isLoading = true;
      });

      Future.delayed(Duration(seconds: 3), () {
        setState(() {
          if (itemCount + 10 < numbers.length) {
            scrollPosition = itemCount;
            itemCount = itemCount + 10;
            isLoading = false;
          } else {
            scrollPosition = numbers.length;
            itemCount = numbers.length;
            isLoading = false;
          }
        });
       // _scollToPosition(); this is the cod that doesn't work
      });

    }
  }

// Function that doesn't work
  void _scollToPosition() {
    _controller.jumpTo(scrollPosition.toDouble());
  }


  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: isLoading
            ? CircularProgressIndicator()
            : NotificationListener<ScrollNotification>(
                onNotification: (ScrollNotification scrollNotification) {
                  if (scrollNotification is ScrollEndNotification) {
                    if (scrollNotification.metrics.pixels ==
                        scrollNotification.metrics.maxScrollExtent) {
                      if (itemCount == numbers.length) {
                        return true;
                      }
                      _onEndScroll(scrollNotification.metrics);
                    }

                    return false;
                  }
                  return false;
                },
                child: ListView.builder(
                  shrinkWrap: true,
                  controller: _controller,
                  itemCount: itemCount,
                  itemBuilder: (BuildContext context, int index) =>
                      TextAndIconWidget(
                    label: numbers[index].toString(),
                  ),
                ),
              ),
      ),
    );
  }

This link explains the problem with scrolling to a specific position with ListView and unfortunately SingleChildScrollView which has the scroll capability you want doesn't have the itemCount property you need

So what you want to do is use the part of the code above that detects when you are at the bottom of the list and then query firebase for the next set of brew there are a number of ways to query firebase. You can find the documentation here. You want to find the best way to sort your brews from looking at the github I think your best bet is alphabetic. So what you would do is for querys is

Firestore.instance.collection('brews').where('name', isLessThanOrEqualTo: NameOfLastBrewYouWantLoaded).getDocuments();
Firestore.instance.collection('brews').where('name', isGreaterThanOrEqualTo: NameOfStartingBrew).where('name', isLessThanOrEqualTo: NameOfEnding).getDocuments(); //if your getting duplicates change isGreaterThanOrEqualTo to isGreaterThan and same for isLessThanOrEqualTo
Firestore.instance.collection('brews').where('name', isGreaterThanOrEqualTo: NameOfLastBrewYouLoaded).getDocuments();

These 3 queries would be your initial query than your query for you would you for every query other except the last one.

I hope this wasnt too confusing

wcyankees424
  • 2,554
  • 2
  • 12
  • 24
  • thank you..i'll try this out..and this will tell you why to not load all the data at once (https://youtu.be/poqTHxtDXwU) – alex Apr 08 '20 at 02:21
  • I am aware of this concept. ```ListView.builder``` lazy loads its data so it only loads the data that is displayed on screen. Flutter takes care of this for you. You just have to worry about grabbing it from firebase accordingly it wasn't until your last post that I realized why you were trying to do what you were doing. Thats why I was confused. – wcyankees424 Apr 08 '20 at 02:26
  • I'm working on the query part so instead of using the stream where it calls the list of all brews ..i have to call them via scroll ..and also for sorting i'm adding timestamp so that it doesn't clash with other names..thank you ..i hope this works out..:).. – alex Apr 08 '20 at 06:05
  • your going to make function that take two parameter the two query parameters and then your going to take the middle query forget about the other two I over complicated things. So for the first query your two parameters would be 'A' to the name of the last beer you wanted displayed. If you get stuck check out that link. See how far you get by tomorrow :) – wcyankees424 Apr 08 '20 at 06:24
  • then you would call that function you created via the NotificationListener – wcyankees424 Apr 08 '20 at 06:26
  • I'm sorry if this is asking too much ..please bear with me :D ..i've seen like almost every video there is on pagination before i posted here but didn't work out .. i tried creating functions but maybe i'm missing out on something as i've been into coding only since about two weeks.. i'd really appreciate if you can tell me what changes do i need to make here ..and also take a look at this(https://github.com/myvsparth/flutter_firebase_pagination/blob/master/lib/main.dart) i tried the function in there as well.. – alex Apr 08 '20 at 07:48
  • i didn't forget about you just busy If you are willing to invest some money into learning to code I would suggest looking into taking some online courses udemy has some good options never pay full price though they do sales all the time. this is my recommendation but they have a bunch and for $10 it is a great value. https://www.udemy.com/course/learn-flutter-dart-to-build-ios-android-apps/ – wcyankees424 Apr 09 '20 at 01:13
  • no problem..I'm aware of the udemy courses but at present i would try to get as much as i can from the tutorials and examples ..thanks for the suggestion though..:) – alex Apr 09 '20 at 04:10