2

I need to display a listview in Flutter with data from firestore. Then I want the user to be able to filter the listview by typing his query in a textfield in the appbar. This is the code I came up with for the listview:

_buildAllAds() {

  return StreamBuilder(
    stream: Firestore.instance.collection("Classificados")
    .orderBy('title').snapshots().map((snap) async {
      allAds.clear();
      snap.documents.forEach((d) {
        allAds.add(ClassificadoData(d.documentID,
          d.data["title"], d.data["description"], d.data["price"], d.data["images"] ));
       
      });

    }),
    builder: (context, snapshot) {

      // if (!snapshot.hasData) {
      //  return Center(child: CircularProgressIndicator());
      //  }
      //else{
      //}
      if (snapshot.hasError) {
        print("err:${snapshot.error}");
      }
      
      return ListView.builder(
        itemCount: allAds.length,
        itemBuilder: (context, index) {
          ClassificadoData ad = allAds[index];
          return ClassificadosTile(ad);

        });
    });

}

The reason I save the stream data in the List allAds of type ClassificadoData (data items are ads) is because I can then copy it to another List filteredAds on which the user can perform filtering. And the reason I need a stream for allAds is because I want users to be able to see additions/updates in real time. So this code "works" but it feels a bit awkward and I also can't do nothing with the builder since snaphot remains null all the way (can't show loader during initial data fetch, for example). Was wondering if there's maybe a more solid way for doing what I want and if it's possible to get a reference to the snapshots down to the builder.

Jaime
  • 824
  • 1
  • 9
  • 29
  • I am not sure if I've understood your issue. Could you please expand on what you mean when you say "I want and if it's possible to get a reference to the snapshots down to the builder."? It is also a bit confusing when you say that the code works but the snapshot remains null. – J. S. Jan 03 '20 at 09:10
  • i suggest you use flutter search it's already implemented not to reinvent the wheel. check this question https://stackoverflow.com/questions/58908968/how-to-implement-a-flutter-search-app-bar – Salma Jan 03 '20 at 10:14
  • @JoãoSoares snapshot = null but the LisView.builder gets populated just the same by allAds. That's what I meant by "awkward". – Jaime Jan 03 '20 at 13:20
  • @Salma.With Flutter ShowSearch the problem remains to show initial data in a stream (should react to changes in backend) and convert the stream data in a list that can be searched (otherwise we would need to fetch and filter data from the db each time as the user types in his query). – Jaime Jan 03 '20 at 13:49

1 Answers1

4

You seem to be mixing two different concepts of using Streams and Stream related Widgets. Ideally you would either use a StreamBuilder and use the data you get from the stream directly on the Widget, or listen to the data and update a variable that is then used to populate your ListView. I've build the latter as an example from your code:

@override
initState(){
  _listenToData();
  super.initState();
}

_listenToData(){
  Firestore.instance.collection("Classificados")
    .orderBy('title').snapshots().listen((snap){
    allAds.clear();
    setState(() {
      snap.documents.forEach((d) {
        allAds.add(ClassificadoData(d.documentID,
          d.data["title"], d.data["description"], d.data["price"], d.data["images"] ));
      });
    });
  });
}

_buildAllAds() {
  return ListView.builder(
    itemCount: allAds.length,
    itemBuilder: (context, index) {
      ClassificadoData ad = allAds[index];
      return ClassificadosTile(ad);
    }
  );
}
J. S.
  • 8,905
  • 2
  • 34
  • 44
  • Thank u for your answer. That was exactly my first approach. Problem is the listvew is not updated in real time when the backend gets updated, since the listener is called only in initstate. Like this, if the db gets updated, the listener will fire for sure, but how do I propagate the update to the build? – Jaime Jan 03 '20 at 20:48
  • Once you start listening to a Firestore collection you don't need to re-listen on every rebuild. You just need to do it once on the initState. The listen will fire if there is a change directly on the collection you are listening to. – J. S. Jan 03 '20 at 21:14