How to get a CloudFirestore nested collection into the ExpasionTile childrens?

2,551 views
Skip to first unread message

jobel...@gmail.com

unread,
Jun 26, 2018, 10:43:53 AM6/26/18
to Flutter Dev
Hello, 
I cannot figure it out how to retrieve a nested collection in CloudFirestore and use the nested collection to create the childrens of a ExpansionTile.

The basic structure of CloudFirebase is:

Collection projects: 
 - name
- Collection surveys:
   - surveyName
   - Collection stations:
       - name
       - geopoint


I want to show  within the `ExpansionTile` , the project `name` as title, and childrens all the surveys using their name in the ListTile.

Any help would be much aprecciated!

class SurveysItems {
final String surveyName;
final String surveyKey;
const SurveysItems({this.surveyName, this.surveyKey});
factory SurveysItems.fromDocument(DocumentSnapshot document) {
return SurveysItems(
surveyName: document['surveyName'], surveyKey: document.documentID);
}
}

class ProjectItem {
final String name;
final String projectKey;
const ProjectItem({this.name, this.projectKey});
factory ProjectItem.fromDocument(DocumentSnapshot document) {
return ProjectItem(
name: document['name'],
projectKey: document.documentID,
);
}
}

class StationItems {
final String name;
final String stationKey;
const StationItems({this.name, this.stationKey});
factory StationItems.fromDocument(DocumentSnapshot document) {
return StationItems(
name: document['name'], stationKey: document.documentID);
}
}


class ProjectList extends StatelessWidget {
ProjectList({this.firestore});

final Firestore firestore;

@override
Widget build(BuildContext context) {
return StreamBuilder<QuerySnapshot>(
stream: firestore.collection('projects').snapshots(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (!snapshot.hasData) return const Text('Loading...');
final int projectsCount = snapshot.data.documents.length;
return new ListView.builder(
itemCount: projectsCount,
itemBuilder: (_, int index) {
final DocumentSnapshot document = snapshot.data.documents[index];
//final CollectionReference surveysCollection = document.reference.collection('surveys');
final ProjectItem projectItem = ProjectItem.fromDocument(document);

Future<List<SurveysItems>> surveyItems = document.reference.collection('surveys').getDocuments()
.then((docs){

return docs.documents.map(
(d){ SurveysItems.fromDocument(d); }).toList();

});

return ExpansionTile(
title: Text(projectItem.name),
              // the following line does not work as the method map does not exist for the Future.
children: surveyItems.map((SurveysItems item){ return ListTile(title: Text(item.surveyName),); }).toList());


},
);
},
);
}
}

jobel...@gmail.com

unread,
Jun 27, 2018, 3:19:05 AM6/27/18
to Flutter Dev
I found my solution, I assume there would be more elegant solutions, but the main piece that I was missing was:

List<Widget> surveysList = [];
documents.forEach((doc) {
PageStorageKey _surveyKey =
new PageStorageKey('${doc.documentID}');

surveysList.add(ListTile(
key: _surveyKey,
title: Text(doc['surveyName']),
));
});
return Column(children: surveysList);
})


Final implementation:

class ProjectList extends StatelessWidget {
ProjectList({this.firestore});

final Firestore firestore;

@override
Widget build(BuildContext context) {
return StreamBuilder<QuerySnapshot>(
stream: firestore.collection('projects').snapshots(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (!snapshot.hasData) return const Text('Loading...');
        //final int projectsCount = snapshot.data.documents.length;
List<DocumentSnapshot> documents = snapshot.data.documents;
return ExpansionTileList(
firestore: firestore,
documents: documents,
);
},
);
}
}

class ExpansionTileList extends StatelessWidget {
final List<DocumentSnapshot> documents;
final Firestore firestore;

ExpansionTileList({this.documents, this.firestore});

List<Widget> _getChildren() {
List<Widget> children = [];
documents.forEach((doc) {
children.add(
ProjectsExpansionTile(
name: doc['name'],
projectKey: doc.documentID,
firestore: firestore,
),
);
});
return children;
}

@override
Widget build(BuildContext context) {
return ListView(
children: _getChildren(),
);
}
}

class ProjectsExpansionTile extends StatelessWidget {
ProjectsExpansionTile({this.projectKey, this.name, this.firestore});

final String projectKey;
final String name;
  final Firestore firestore;

@override
Widget build(BuildContext context) {
    PageStorageKey _projectKey = PageStorageKey('$projectKey');

return ExpansionTile(
key: _projectKey,
title: Text(
name,
style: TextStyle(fontSize: 28.0),
),
children: <Widget>[
StreamBuilder(
stream: firestore
.collection('projects')
.document(projectKey)
.collection('surveys')

.snapshots(),
builder:
(BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (!snapshot.hasData) return const Text('Loading...');
              //final int surveysCount = snapshot.data.documents.length;
List<DocumentSnapshot> documents = snapshot.data.documents;

List<Widget> surveysList = [];
documents.forEach((doc) {
PageStorageKey _surveyKey =
new PageStorageKey('${doc.documentID}');

surveysList.add(ListTile(
key: _surveyKey,
title: Text(doc['surveyName']),
));
});
return Column(children: surveysList);
})
],
);
}
}


Cheers!

Happy coding!
Reply all
Reply to author
Forward
0 new messages