I'm attempting to create a listview from data I have in Firestore using FutureBuilder in Flutter but from documentation and other similar questions I cannot seem to make what I'm trying to do work.
I have two collections on Firestore, one that is for users
and one for items items
.
The users
collection contains an array of ids for items
.
I want to access the user
's item
list, get all of the item
ids and then user them to get each individual item's
data.
Currently I have something that sort of works, but not exactly in the way I want as I cannot sort the list before it creates the ListView
, and I know it is by far not optimised.
This is a simplified version of the code I have used to achieve this.
The following code is for accessing Document snapshots from Firestore.
Future getUserInfo(User user) async{
// Gets Current user's collection
DocumentReference userIdRef = usersCollection.document(user.getUid());
DocumentSnapshot userIdSnapshot = await userIdRef.get();
return userIdSnapshot.data;
}
Future getItemInfo(String itemId) async{
DocumentReference itemIdRef = itemCollection.document(itemId);
DocumentSnapshot itemIdSnapshot = await itemIdRef.get();
return itemIdSnapshot.data;
}
In the Widget tree I have two FutureBuilders, one nested inside the other to create a list. (I've removed details unessessary for the question
class _TestState extends State<Test> {
FirestoreDatabase firestoreDatabase = new FirestoreDatabase();
@override
Widget build(BuildContext context) {
final user = Provider.of<User>(context);
return Scaffold(
body: getUserItemsFromFirestore(user),
);
}
Widget getUserItemsFromFirestore(User user) {
FirestoreDatabase firestore = new FirestoreDatabase(uid: user.getUid());
return FutureBuilder(
future: firestore.getUserInfo(user),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return LoadingSpinner();
} else if (snapshot.connectionState == ConnectionState.done ||
snapshot.connectionState == ConnectionState.active) {
//List<MedicationRegime> medicationList = snapshot.data ?? [];
return ListView.builder(
itemCount: snapshot.data['item'].length,
itemBuilder: (context, index) {
return getItemList(
snapshot.data['item'][index], user, index);
},
);
} else {
return null;
}
});
}
Widget getItemList(String itemID, User user, int index) {
FirestoreDatabase firestore = new FirestoreDatabase(uid: user.getUid());
return FutureBuilder(
future: firestore.getItemInfo(itemID),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return LoadingSpinner();
} else if (snapshot.connectionState == ConnectionState.done ||
snapshot.connectionState == ConnectionState.active) {
List itemList = [];
Item item = new Item(
itemID: itemID,
name: snapshot.data['name'],
type: snapshot.data['type']
);
itemList.add(item);
return ListView.builder(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: itemList.length,
itemBuilder: (context, index) {
return Card(
child: ListTile(
leading: Icon(itemList[index]
.getitemIcon()),
title: Text(
itemList[index].getName(),
),
subtitle: Text(itemList[index].getType()),
],
),
);
);
});
} else {
return null;
}
});
}
}
Would there be a way to incorporate both of these into the one FutureBuilder, as I need getUserInfo()
to have run before I can call getItemInfo
so I cannot use Future.wait([getUserInfo, getItemInfo])
. Thanks