1
votes

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.

1
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. - João Soares
i suggest you use flutter search it's already implemented not to reinvent the wheel. check this question stackoverflow.com/questions/58908968/… - Salma
@JoãoSoares snapshot = null but the LisView.builder gets populated just the same by allAds. That's what I meant by "awkward". - Jaime
@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

1 Answers

4
votes

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);
    }
  );
}