0

I am attempting to populate a ListView.builder with data from multiple nodes from my instance of Firebase Realtime Database.

I am interested in listening to changes on the chats node (and updating the listview when they occur), but less interested in real-time updates on the chats-details node.

chats
-- 'chat1' 
---- 'keyA' : 'This is some text'
---- 'keyB' : 'This is some text'

-- 'chat2' 
---- 'keyA' : 'This is some text'
---- 'keyB' : 'This is some text'

chats-details
-- 'chat1' 
---- 'keyC' : 'This is some text'
---- 'keyD' : 'This is some text'

-- 'chat2' 
---- 'keyC' : 'This is some text'
---- 'keyD' : 'This is some text'

Ideally, all data for chat1, chat2...etc would be appended to Object (myChats in example below) and fed into the ListView.

Any help would be greatly appreciated. My current code is below. This code currently does not automatically populate the ListView.

  // Node 1 - Listen to changes
  chatsRef = FirebaseDatabase().reference().child('chats');

  // Node 2 - Update when node 1 is updated
  chatsDetailsRef = FirebaseDatabase().reference().child('chats-details');

  @override
  Widget build(BuildContext context) {
    List<Chats> myChats = [];

    return Scaffold(
        appBar: AppBar(),
        body: StreamBuilder(
          stream: chatsRef.onValue,
          builder: (context, snap) {

            if (snap.hasData && !snap.hasError && snap.data.snapshot.value != null) {
              Map data = snap.data.snapshot.value;

              data.forEach((index, data) {
                chatsDetailsRef.child(index).once().then((DataSnapshot snapshot) {

                  Chats currentChat = Chats.fromMap(data);

                  if (snapshot.value == null) {
                    Chat emptyChatDetails = Chat();
                    currentChat.chatDetails = emptyChatDetails;
                  } else {
                    Chat foundChatDetails = ChatDetails.fromMap(snapshot.value);
                    currentChat.chatDetails = foundChatDetails;
                  }

                  myChats.add(currentChat);

                });


              });
              return ListView.builder(
                itemCount: myChats.length,
                itemBuilder: (context, index) {
                  return ListTile(
                    title: Text(myChats[index].title),
                    subtitle: Text(myChats[index].chatDetails.detail),
                  );
                },
              );
            } else {
              return Center(child: Text("No data"));
            }
          },
        ),
    );
  }
}
Jack
  • 49
  • 5
  • The following post solved the issue: https://stackoverflow.com/questions/59061225/how-do-i-join-data-from-two-firestore-collections-in-flutter/59061226#59061226 – Jack Jan 11 '20 at 16:49

1 Answers1

1

Did you try making a call to setState whenever you add items to myChats?

setState(() {
    myChats.add(currentChat);
});

https://api.flutter.dev/flutter/widgets/State/setState.html

Also, you currently redefine the myChats array every time the build function runs, meaning it will clear all chats in there whenever the widget is rebuilt. If you want those chats to stay, you will have to declare that array as a member of the class itself

Yusef
  • 306
  • 1
  • 5
  • Thanks for your reply, Yusef. I tried running setState(). Still tinkering, however, it doesn't appear to have fixed the issue. Additionally, when I run, I see a continuous stream of data getting printed to the logs. Does the code above `myChats.add(currentChat);` look ok to you? I've also gone ahead and moved `myChats` out side the build method -- thanks for that tip. – Jack Jan 10 '20 at 15:36
  • It looks fine to me. What is the stream of data being printed? – Yusef Jan 11 '20 at 01:37
  • Found this answer which seems to be helping https://stackoverflow.com/questions/59061225/how-do-i-join-data-from-two-firestore-collections-in-flutter/59061226#59061226 – Jack Jan 11 '20 at 14:26