Flutter - make api call inside Listview - flutter

I am calling an api, which will return a list of items (workouts), and items will be shown in a ListView. but I also need to call another api for each item of the ListView to fetch the score of that workout (if there is already a score) and show the score to each workout according to their id. How can I resolve this scenario.? I am using bloc and this is how I am fetching the workouts
Future<void> _onLoadingWod(
OnLoadingWodEvent event, Emitter<WhiteboardState> emit) async {
emit(state.copyWith(isWodLoading: true));
final listWods =
await WhiteboardService().getListWod(state.selectedDay.toString());
emit(state.copyWith(
isWodLoading: false, listWods: listWods));
}
some workouts may not have a score yet, in that case, I show in the listview a button to log a score for each workout.
I tried something like this:
final listResults = await Stream.fromIterable(listWods)
.asyncMap((wod) => WhiteboardService().getresult(wod.id))
.toList();
but since some workouts may not have result, is showing error.
how can a link workouts with results and show then in a listview? pls any help o guide is appreciated.

As I understand, it can be done from a loop. You have to create a model class for results that include the workout id. Then you can loop through it and find the relevant workout from the workout list and then assign the results for it.
there is an example hope it will help.
*dummy model classes
class Workouts {
final int id;
Result? result;
Workouts({
required this.id,
this.result,
});
}
class Result {
final int workoutId;
final String result;
Result({
required this.workoutId,
required this.result,
});
}
*assign results to workout list
void asignResults() {
///for each [results]
for (Result result in listResults) {
listWorkouts
.firstWhere((workout) => workout.id == result.workoutId)
.result = result;
}
listWorkouts.forEach((element) {
print(element.toString());
});
}
I think if you can do this from the backend it will be more efficient than this approach. (eg:- join query in sql)

Related

Cant retrieve certain fields from the parsed list of the Firestore database

I am building a restaurant app in which I have used Firestore as my backend. I have stored the details of the menu in a collection Menu and each menu item in specific documents. Firstly, is that a good data model, or should I have the whole menu in the same document?
Secondly, the problem is while I retrieve the the collection and the docs, I am not being able to access some fields. If there are 4 documents and all of them contains the field 'Name' and data in the field. But when I fetch the data, parse it inot the list and have the command Menu[index]['Name] only two of the names in the documents are displayed while the other two return null.
class MenuController extends GetxController {
final CollectionReference _menulsit =
FirebaseFirestore.instance.collection('Menu');
Future getmenu() async {
List Menulist = [];
try {
await _menulsit.get().then((QuerySnapshot snapshot) {
snapshot.docs.forEach((element) {
Menulist.add(element.data());
});
});
return Menulist;
} catch (e) {
return null;
}
}
}
While I parse it into a list and print the list, the data is retrieved and is printed in the console. There is the field 'Name' printed on the console but when I try to access it from the list it returns null. The same fields on some documents are returned but the same fields on some other documents are returned to be null.
I have used the list from the class, made a method, and provided a list here with the data retrieved. I need to use the data in a listview.seperated.
class _FoodmenuState extends State<Foodmenu> {
List menulist = [];
#override
void initState() {
super.initState();
fetchmenu();
}
Future fetchmenu() async {
dynamic resultmenu = await MenuController().getmenu();
if (resultmenu == null) {
return Text('Unable to retrive data');
} else {
setState(() {
menulist = resultmenu;
});
}
}
#override
Widget build(BuildContext context) {
return Column(children: [
Container(
height: 228,
child: ListView.separated(
scrollDirection: Axis.horizontal,
itemBuilder: ((context, index) => _menucontent(index, menulist)),
separatorBuilder: ((context, index) {
return SizedBox(
width: 18,
);
}),
itemCount: menulist.length))
]);
}
}
While I print the list there is the field "Name" but I can't access it.
Print(menu)
I/flutter (31598): [{Name: Cheese Burger}, {Name : Buffalo Wings}, {Name : Pasta Bolognese }, {Name : Chicken MoMo}]
Print(menu[1])
I/flutter (31598): {Name : Buffalo Wings}
Print(menu[1]['Name']
I/flutter (31598): null
Its better to store each menu item in separate document as it would enable to fetch only some menu items based on some conditions.
Regarding menu[1]['Name'] value printed as null:
As Print(menu) is giving correct JSON response, I think there is extra space after Name word in firestore document. You might have added this data manually :). Please refer below screenshot.
First of all you should consider defining data types as it would lower chances of error and provide better suggestion if data types are mentioned. Make a class of MenuItem and make menu items as it might help when you want to add any item in overall app. Below is a example to help you understand.
class MenuItem {
final String name;
final int price;
final String description;
//you can add extra field here
MenuItem(
{required this.name, required this.price, required this.description});
MenuItem.fromJson(Map<String, dynamic> json)
: name = json['name'],
price = json['price'],
description = json['description'];
}
Future getmenu() async {
List<MenuItem> menulist = [];
try {
await _menulsit.get().then((QuerySnapshot snapshot) {
snapshot.docs.forEach((element) {
menulist.add(MenuItem.fromJson(element.data()));
});
});
return menulist;
} catch (e) {
return menulist;
}
}
Now if you want to access name you can try like this menulist[0].name beside this if you type menulist[0]. it will give you suggestion whatever a menuItem can hold.
EDIT:
check it out and cast it from beginning as if Object to <Map<String, dynamic>> error occurs
final CollectionReference<Map<String, dynamic>> _menulsit =
FirebaseFirestore.instance.collection('Menu');
Future getmenu() async {
List<MenuItem> menulist = [];
try {
await _menulsit.get().then((QuerySnapshot<Map<String, dynamic>> snapshot) {
snapshot.docs.forEach((element) {
menulist.add(MenuItem.fromJson(element.data()));
});
});
return menulist;
} catch (e) {
return null;
}
}

Getting all documents uids from firestore and add them to a list .flutter

I created a new collection named users on my firestore project. Im trying to get a list of all auto generated id's in that collection. So far I tried
late List<String> userID = [];
Future getID() async {
await FirebaseFirestore.instance.collection('users').get().then(
(snapshot) => snapshot.docs.forEach((document) {
userID.add(document.reference.id);
}),
);
}
But whenever I try to access the Strings of id's in the list , it returns an empty list
getID is a future method. It will take some to fetch data. After getting data you need to call setState to update the UI. You dont need to await and .then same time
try
Future getID() async {
FirebaseFirestore.instance.collection('users').get().then((snapshot) {
snapshot.docs.forEach((document) {
userID.add(document.reference.id);
});
setState(() {});
});
}
It would be great to use FutureBuilder for future method.

Create a list inside an item of another list

I have a list of teams to which the logged in user belongs to in my application. Within each team there is a list with the Uids of each team member (teamMembersUid). There is also an empty list in which the information of each user (teamMembers) must be inserted.
Objective: I want to take the Uids of each user in teamMembersUid, extract their information from the database (Firebase firestore) and introduce it into teamMembers list. Here is the team model with the lists:
class TeamModel {
String? uid;
String? teamName;
List<String>? teamMembersUid;
List<UserModel>? teamMembers;
List<String>? publicationsUid;
List<String>? notifications;
List<String>? instancesUid;
TeamModel(
{this.uid,
this.teamName,
this.teamMembersUid,
this.teamMembers,
this.instancesUid,
this.notifications,
this.publicationsUid});
//receiving data from server
factory TeamModel.fromMap(map) {
return TeamModel(
uid: map['uid'],
teamName: map['teamName'],
teamMembersUid: map['teamMembersUid'] is Iterable
? List.from(map['teamMembersUid'])
: null,
teamMembers:
map['teamMembers'] is Iterable ? List.from(map['teamMembers']) : null,
publicationsUid: map['publicationsUid'] is Iterable
? List.from(map['publicationsUid'])
: null,
notifications: map['notifications'] is Iterable
? List.from(map['notifications'])
: null,
instancesUid: map['instancesUid'] is Iterable
? List.from(map['instancesUid'])
: null,
//List.from(['teamMembersUid']), //castFrom adapts teamMembersUid to be a List
);
}
The following function (getTeamsInfoWithUsers) is responsible for:
Create a list with the teams to which the user belongs from firestore.
Extract the Uids of each member of each team.
Get the information from each user from firestore.
Create a list with the information of each user of each team and enter it in teamMembers.
UserModel userData;
List<TeamModel> retVal = [];
try {
//Create a list with the teams to which the user belongs from firestore
final data = await _firestore
.collection("teams")
.where("teamMembersUid", arrayContains: userUid)
.get();
List<TeamModel> data_m =
List.from(data.docs.map((doc) => TeamModel.fromMap(doc)));
//Extract the Uids of each member of each team.
retVal = data_m
.map((team) {
team.teamMembersUid!.map((userUid) async {
//Get the information from each user from firestore.
userData = await getUserInfo(userUid);
//Create a list with the information of each user of each team and enter it in teamMembers.
team.teamMembers!.add(userData);
});
})
.cast<TeamModel>()
.toList();
} catch (e) {
print(e);
}
return retVal;
}```
Problem: The current user belongs to 4 teams and each team has 3 users. Debugging I put a breakpoint in team.teamMembers!.add(userData); line. Since there are 4 teams and each team has 3 users you should see the code stop on that line 12 times, 3 for each team. Instead, it only stops 3 times and doesn't seem to create the list of teamMembers in the data_m variable either. I don't understand why it doesn't work.
Error:
Null error
how about this
retVal = data_m
.map((team) {
team.teamMembersUid!.map((userUid) async {
userData = await getUserInfo(userUid);
team.teamMembers!.add(userData);
}).toList();
})
.cast<TeamModel>()
.toList();
VS

How to change index of an item in list in Flutter

I am working on a messaging app and I need help on a feature. Chat Users are stores inside a list and it is shown in a List View. When new message come to each chatuser(item in the list) I need it change that item as first. So recent contacts will be shown first like other social medias. I need to know how to change index of it to first. For swapping I need to take two items which in this case I cant do. So when new message comes to an item that item should be the first in that list. What should I do
have a look at this:
class Contact {
final List<String> messages;
final String name;
Contact({required this.name, this.messages = const []});
}
void main() {
List<Contact> contacts = [Contact(name: "userA"), Contact(name: "userB"), Contact(name: "userC")];
void receiveMessage(String username, String message) {
final Contact user = contacts.where((e) => e.name == username).first;
contacts.remove(user);
user.messages.add(message);
contacts.insert(0, user);
}
receiveMessage("userB", "hello");
receiveMessage("userC", "helloooo");
receiveMessage("userB", "hello000000000");
for (var contact in contacts) {
print(contact.name);
for (var message in contact.messages) {
print(message);
}
print("------------------------");
}
}

Flutter Firestore Wait untill all data read

i am trying to build an e commerce app. I got stuck while i was trying to build shopping cart. I read ids of product from cart collections and read products by those ids. Need to wait untill all product models are read and then loading state should turn false. But i can read only ids in cart and state turn false. When it happens, cart looks still empty even there is something in it. How can i solve this issue? I could not grab the idea of asynchronous function i guess. Thanks.
Read data from carts collection;
Future <void> yukleme () async
{
CollectionReference cartReference = FirebaseFirestore.instance.collection("carts");
DocumentSnapshot snapshot = await cartReference.doc("1").get();
cart_model = Cart_Model.fromJson(snapshot.data());
print(cart_model.product_ids);
setState(() {
loading = false; // it turns false when cart model is done but product models havent read
});
return;
}
Cart model which contains id and product models in it.
Cart_Model.fromJson (Map<String, dynamic> snapshot)
{
product_ids = snapshot["product_ids"].cast<String>() ;
if (product_ids.length > 0 && product_ids != null )
{
product_ids.forEach((String id) {
productReference.doc("$id").get().then((DocumentSnapshot snapshot){
ProductModel productModel = ProductModel.fromJson(snapshot.data());
});
});
}
}
Here where i call yukleme() function;
class _CartState extends State {
bool loading = true;
Cart_Model cart_model;
#override
Widget build(BuildContext context) {
if(loading == true)
{
yukleme();
}
...................