Condition does not work when using a streamBuilder in Flutter

Viewed 2538

I'm trying to implement a screen that displays data from Firebase but I want the streambuilder to check if the database is empty, if it's empty I want it to show a text saying "no data" but if it's not, I want it to show the data from firebase.

This is the code I have but it does not work as expected, it just shows me a blank screen when there is no data(it works fine when I have data in the database, I just don't want the user to see a blank screen when there is no data). Can you advise what is wrong with this code? what is the best way to implement this?

@override
  Widget build(BuildContext context) {
    double height = responsive.height(context);
    double width = responsive.width(context);
    var stream = Firestore.instance
        .collection('favoritePost')
        .document(widget.currentUserId)
        .collection('favoritePost')
        .orderBy('timestamp', descending: true)
        .snapshots();
    return Scaffold(
      backgroundColor: kBackgroundColorForAllScreens,
      appBar: PreferredSize(
        preferredSize: Size.fromHeight(responsive.height(context) / 20),
        child: SimpleAppBar(
          label: 'Tus Favoritos',
          witdh: responsive.width(context) / 4.7,
          onPressed: () {
            Navigator.pop(context);
          },
        ),
      ),
      body: Column(
        children: <Widget>[
          Expanded(
            child: Container(
              child: StreamBuilder(
                stream: stream,
                builder: (context, snapshotPost) {
                  if (snapshotPost.hasData) {
                    return ListView.builder(
                      itemExtent: height / 3.3,
                      itemCount: snapshotPost.data.documents.length,
                      itemBuilder: (BuildContext context, int index) {
                        Reviews reviews = Reviews.fromDoc(
                          snapshotPost.data.documents[index],
                        );
                        Provider.of<UserData>(context).reviews = reviews;
                        return ReviewsMenu(
                          reviews: reviews,
                          user: widget.user,
                          currentUserId: widget.currentUserId,
                          showDialogForDelete: true,
                          comingFromFavorite: true,
                        );
                      },
                    );
                  } else {
                    return Center(
                      child: Text('NO DATA'),
                    );
                  }
                },
              ),
            ),
          ),
        ],
      ),
    );
  }
3 Answers

Dont initialize streams in build method

Use StatefulWidget and initialize the stream in State.initState


// inside, class [...] extends State<[...]>

Stream stream;

@override
void initState() {
  super.initState();
  stream = Firestore.instance
        .collection('favoritePost')
        .document(widget.currentUserId)
        .collection('favoritePost')
        .orderBy('timestamp', descending: true)
        .snapshots();

}

inside StreamBuilder.builder where Snapshot.hasData check if the number of reviews are greater then 0

if (snapshot.hasData) {
  if (snapshot.data.documents.length == 0) {
    return Center(child: Text('NO DATA'));
  } 
}

then use it normally as you already have

You'll need to check if snapshot.data == null:

if (snapshot.data == null || snapshot.data.documents.length == 0) {
  return Center(child: Text('NO DATA'));
}

StreamBuilder snapshot will not have any data until it has completed the lookup. So, it's always best to check for null on any Builder (Future or Stream).

Updated answer The length part for me was not working so I structured it something like this, just a keyword difference here.

stream: stream,
    builder: (BuildContext context, snapshot) {
      if (snapshot.hasData) {
        if (snapshot.data.docs.isEmpty) {
          return new InfoList1();
        } else {
          return new MainHomeScreen();
        }
      } else {
        return new Loading();
      }
    });

And initialized the stream by calling State.initState, if someone has the same problem as me.

Related