Reputation: 407
I am trying to retrieve data from the firebase twice inside the FutureBuilder, first time the 'future:' parameter takes care of retrieving the data. However, the second time when I try to retrieve 'restaurant' data from firebase, I am getting a null error because I can't wait for the 'getRestauran()' function to finish executing. If I add 'await' before the function it gives an error because 'async' can't be applied to the 'builder' function.
Is there a way to make this work?
Future<Restaurant> getRestaurant(String restaurantId) async {
Map<String, dynamic> restaurantData;
String id;
await FirebaseFirestore.instance
.collection('restaurants')
.doc(restaurantId)
.get()
.then((value) {
restaurantData = value.data();
id = value.id;
});
print(restaurantData);
final restaurant1 = Restaurant(
id: id,
name: restaurantData['name'],
description: restaurantData['description'],
// cuisine: List<String>.from(restaurant['cuisine']),
imageUrl: restaurantData['imageUrl'],
isAvailable: restaurantData['isAvailable'],
isFavourite: restaurantData['isFavourite'],
pickupTime: restaurantData['pickupTime'].toDate(),
stars: restaurantData['stars'].toDouble(),
location: Location(
address: restaurantData['location']['address'],
city: restaurantData['location']['city'],
latitude: restaurantData['location']['latitude'],
longitude: restaurantData['location']['longitude'],
zipcode: restaurantData['location']['zipcode'],
locality: restaurantData['location']['locality'],
),
// items: restItems,
// reviews: reviews,
);
return restaurant1;
}
@override
Widget build(BuildContext context) {
final cart = Provider.of<Cart>(context);
final order = Provider.of<Order>(context);
// cartItems =
// Provider.of<Cart>(context, listen: false).cartItems.values.toList();
//print(cartItems[0].title);
final Size size = MediaQuery.of(context).size;
return Scaffold(
body:
// cartItems.isEmpty
// ? Center(
// child: Text(
// 'Your Cart is Empty',
// style: TextStyle(
// color: kTextLightColor,
// fontSize: 18,
// ),
// ),
// )
// :
FutureBuilder<List<CartItem>>(
future: cart.fetchCartItems(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
//Navigator.of(context).pushNamed('loading');
return Center(child: CircularProgressIndicator());
}
List<CartItem> cartItems = snapshot.data;
print(cartItems[0].restaurantId);
Map<String, dynamic> restaurantData;
String id;
restaurant = getRestaurant(cartItems[0].restaurantId);
print('$restaurant: Restaurant Data');
// return isComplete
return CartWidget(
restaurant: restaurant,
cart: cart,
cartItems: cartItems,
order: order);
// : CircularProgressIndicator();
}),
);
}
}
Upvotes: 2
Views: 2849
Reputation: 12383
In general, you can't await
inside build methods. You can invoke functions, but you can't await for them. Future builder solves this issue.
In your case, you need two future builders, and you have the first one figured out.
The solution is to go to your `CartWidget`, when you define it, add a required string to it like this, instead of requiring a `restaurant` object, you require a `restaurantId`:
class CartWidget extends StatelessWidget{
final String restaurantId;
const CartWidget({required this.restaurantId});
//.
//.
// the rest of your widget logic, also move this function completely to this widget
//Future<Restaurant> getRestaurant(String restaurantId) async {}
}
Then, inside your build, when it comes to restaurant, use a future builder, and get it using the function you moved here. It will solve your problem.
Upvotes: 2