title: Flutter: Creating a dynamically updating DataTable with multi-collection stream from Firestore
body: <p>So I am (trying to) create a DataTable to dynamically display a bunch of packages (like Amazon or UPS packages) based on Firestore data. The complication is: My data is stored across multiple collections in the database, the 'queue', 'inhouse', and 'students'.</p>
  
  <p>I have created a version of what I want using a ListView.builder and ListViewTiles. Currently it works perfectly, displaying new tiles as new data is added to the queue. Instead of using a ListView, i would like to display all the data in a table (DataTable); however I am having trouble fitting in what I already have (FutureBuilders and StreamBuilders) in a way that would work with a DataTable.</p>
  
  <p>I also have a placeholder DataTable that displays a bunch of dummy packages from a pre-defined list in the exact way that i want.</p>
  
  <p>I've done research on using Provider to provide a rebuilding list to the DataTable widget... But i cant seem to connect the dots when trying to read from multiple collections simultaneously.</p>
  
  <p>Here is the code for my ListView...</p>
  
  <pre><code>import 'package:cloud_firestore/cloud_firestore.dart';
  import 'package:flutter/material.dart';
  
  class QueueDisplay extends StatefulWidget {
    @override
    _QueueDisplayState createState() =&gt; _QueueDisplayState();
  }
  
  class _QueueDisplayState extends State&lt;QueueDisplay&gt; {
    @override
    Widget build(BuildContext context) {
      return Container(
        child: StreamBuilder(
          stream: Firestore.instance.collection('queue').snapshots(),
          builder:(context, snapshot){
            if (!snapshot.hasData){
              return (Center(child: CircularProgressIndicator()));
            } else {
              return ListView.builder(
                itemCount: snapshot.data.documents.length,
                itemBuilder: (context, index) {
                  DocumentSnapshot queueDoc = snapshot.data.documents[index];
                  return Column(
                    children: &lt;Widget&gt;[
                      FutureBuilder(
                        future: Firestore.instance.collection('students').document('${queueDoc.data['owner']}').get(),
                        builder: (BuildContext context, AsyncSnapshot studentSnap) {
                          return FutureBuilder(
                            future: Firestore.instance.collection('inhouse').where('owner', isEqualTo: queueDoc.data['owner']).getDocuments(),
                            builder: (BuildContext context, AsyncSnapshot packSnap) {
                              if (packSnap.hasData){
                                if(packSnap.data!=null){
                                  return ListTile(
                                      title: Row(
                                        children: &lt;Widget&gt;[
                                          Text('${queueDoc.data['owner']}' + '     '),
                                          Text('${studentSnap.data['name']}' + '     '),
                                          Text('${packSnap.data.documents[0].documentID}'),
                                        ],
                                      )
                                  );
                                }
                              } else {
                                return Center(child: CircularProgressIndicator());
                              }
                              return Center(child: CircularProgressIndicator());
                            },
                          );
                        },
                      )
                    ],
                  );
                },
              );
            }
          },
        ),
      );
    }
  }
  </code></pre>
  
  <p><a href="https://i.stack.imgur.com/b5qcR.jpg" rel="nofollow noreferrer">Functioning ListView Screenshot</a></p>
  
  <p>And here is the code for the placeholder DataTable...</p>
  
  <pre><code>class QueueTable extends StatefulWidget {
    @override
    _QueueTableState createState() =&gt; _QueueTableState();
  }
  
  class _QueueTableState extends State&lt;QueueTable&gt; {
    @override
    Widget build(BuildContext context) {
      return SingleChildScrollView(
        scrollDirection: Axis.horizontal,
        child: Container(
          //color: Colors.grey[200],
          child: DataTable(
            // Table Displaying Queued Packages
              columnSpacing: 8,
              columns: [
                DataColumn(label: Text("Name"),numeric: false, onSort: (i, b) {}),
                DataColumn(label: Text("Location"),numeric: false, onSort: (i, b) {}),
                DataColumn(label: Text("Tracking"),numeric: false, onSort: (i, b) {}),
                DataColumn(label: Text("Carrier"),numeric: false, onSort: (i, b) {}),
                DataColumn(label: Text("Notes"),numeric: false, onSort: (i, b) {}),
                DataColumn(label: Text("Received"),numeric: false, onSort: (i, b) {}),
              ],
              rows: packages.map((package) =&gt; DataRow(
                  onSelectChanged: (b) {},
                  cells: [
                    DataCell(Text(package.owner.name), onTap: (){}),
                    DataCell(Text(package.location), onTap: (){}),
                    DataCell(Text(package.tracking)),
                    DataCell(Text(package.carrier)),
                    DataCell(Text(package.notes), onTap: (){}),
                    DataCell(Text(package.rDate)),
              ])).toList()
          ),
        ),
      );
    }
  }
  
  Student adam =
      Student('0000004028', 'Adam G', 'adamg@email.net');
  var packages = [
    Package(adam, 'Large', 'USPS', '1/15/2020', '123456', 'Great Dude!'),
    Package(adam, 'Small', 'UPS', '1/16/2020', '1234567', 'Great Guy!'),
    Package(adam, 'Medium', 'FedEx', '1/18/2020', '12345678', 'Great Bro!'),
    Package(adam, 'Floor', 'Amazon', '1/5/2020', '123456789', 'Great Person!'),
  ];
  </code></pre>
  
  <p><a href="https://i.stack.imgur.com/cEmTa.png" rel="nofollow noreferrer">Placeholder DataTable Screenshot</a></p>
  
  <p>Both pieces of code provided should work fine; I just cant seem to combine them into a working dynamic DataTable...</p>
  
  <p>Any suggestions? Thank you!</p>
  
  <p><strong>Update:</strong></p>
  
  <p>So here is my closest try so far...</p>
  
  <p>I made a stream of List and used StreamProvider to provide the stream to the widget creating the DataTable.</p>
  
  <p><a href="https://i.stack.imgur.com/vPTr2.png" rel="nofollow noreferrer">database.dart</a></p>
  
  <p><a href="https://i.stack.imgur.com/p98cD.png" rel="nofollow noreferrer">Provider that only returns null Packages</a></p>
  
  <p>It seems like it <em>would</em> work; if only I could get _queueListFromSnapshot to return the correct value for the Package p. Because of the nested Future.then(){} statements I cant yet figure out how to return the correct value. 
  (Shown in comments of database.dart)</p>
  
  <p><strong>Update 2:</strong></p>
  
  <p>Here is a <a href="https://i.stack.imgur.com/xeHeC.png" rel="nofollow noreferrer">slightly better try</a> using async/await. This requires me to change the return type of the function which causes mismatch farther up because I still want to return a completed List to the StreamProvider... right?</p>