mustafa zaki
mustafa zaki

Reputation: 407

How can I add new item in a list?

class Restaurants with ChangeNotifier {
  List<Restaurant> _restaurants = [];

  List<Restaurant> get getRestaurants1 {
    return [..._restaurants];
  }

  Future<void> fetchAndSetRestaurants() async {
    List<Restaurant> tempRestaurants = [];
    try {
      List<RestaurantItems> restItems = [];
      List<Reviews> reviews = [];

      await FirebaseFirestore.instance.collection('restaurants').get().then(
            (restaurants) => restaurants.docs.forEach(
              (restaurantData) async {
                if (restaurantData.id == null) {
                  print('no id error');
                }
                print('restaurant Id:');
                print(restaurantData.id);
                final Map<String, dynamic> restaurant = restaurantData.data();
                print(restaurant);
                await FirebaseFirestore.instance // Restaurant Items
                    .collection('restaurants')
                    .doc(restaurantData.id)
                    .collection('restaurantItems')
                    .get()
                    .then(
                  (firestoreRestaurantItems) {
                    firestoreRestaurantItems.docs.forEach(
                      (restItemData) {
                        print(restItemData.data());
                        final Map<String, dynamic> restItem =
                            restItemData.data();
                        print('before:');
                        print(restItem['price'].runtimeType);
                        final RestaurantItems newRestaurantItem =
                            RestaurantItems(
                          id: restItemData.id,
                          description: restItem['description'],
                          //imageUrl: restItem['imageUrl'],
                          isVeg: restItem['isVeg'],
                          name: restItem['name'],
                          price: restItem['price'].toDouble(),
                          quantity: restItem['quantity'],
                        );
                        print('After:');
                        print(newRestaurantItem.name);
                        if (newRestaurantItem == null) {
                          print('fail');
                        }

                        restItems.add(newRestaurantItem);
                      },
                    );
                  },
                );
                await FirebaseFirestore.instance // Restaurant Items
                    .collection('restaurants')
                    .doc(restaurantData.id)
                    .collection('reviews')
                    .get()
                    .then(
                  (firestorReviews) {
                    firestorReviews.docs.forEach(
                      (reviewData) {
                        final Map<String, dynamic> review = reviewData.data();
                        print('before:');
                        print(reviewData['text']);
                        final Reviews newReview = Reviews(
                            id: reviewData.id,
                            rating: review['rating'],
                            description: review['description'],
                            text: review['text']);
                        print('after');
                        print(newReview.text);

                        reviews.add(newReview);
                      },
                    );
                  },
                );
                final strings = List<String>.from(restaurant['cuisine']);
                print(strings.runtimeType);
                final newRestaurant = Restaurant(
                  id: restaurantData.id,
                  name: restaurant['name'],
                  description: restaurant['description'],
                  cuisine: List<String>.from(restaurant['cuisine']),
                  imageUrl: restaurant['imageUrl'],
                  isAvailable: restaurant['isAvailable'],
                  isFavourite: restaurant['isFavourite'],
                  pickupTime: restaurant['pickupTime'].toDate(),
                  stars: restaurant['stars'].toDouble(),
                  location: Location(
                    address: restaurant['location']['address'],
                    city: restaurant['location']['city'],
                    latitude: restaurant['location']['latitude'],
                    longitude: restaurant['location']['longitude'],
                    zipcode: restaurant['location']['zipcode'],
                    locality: restaurant['location']['locality'],
                  ),
                  items: restItems,
                  reviews: reviews,
                );

                print(newRestaurant.name);
                tempRestaurants.add(newRestaurant);
                print('temp:${tempRestaurants.length}');
                _restaurants.add(newRestaurant);
                // print('final:${_restaurants.length}');
              },
            ),
          );
      print('_restaurants: ${_restaurants[0].imageUrl}');
      notifyListeners();
     
    } catch (error) {
      print('error in fetchAndSetRestaurants');
      throw error;
    }
  }
}

I am trying to retrieve restaurant data from firestore but I when I add a new restaurant item to my main List (_restaurants), it gives me the following error:

flutter: error in fetchAndSetRestaurants [VERBOSE-2:ui_dart_state.cc(177)] Unhandled Exception: RangeError (index): Invalid value: Valid value range is empty: 0

The _restaurants variable seems to be empty even after adding newRestaurant in it.

Upvotes: 4

Views: 127

Answers (1)

Vadim Popov
Vadim Popov

Reputation: 772

You should use the async-await construct because you are trying to retrieve an item while the data is still fetching.

https://dart.dev/codelabs/async-await

Like that:

final restaurants = await FirebaseFirestore.instance.collection('restaurants').get();
for (final restaurant in restaurants.docs) {
  final items = FirebaseFirestore.instance.collection('restaurants')
                .doc(restaurant.id)
                .collection('restaurantItems')
                .get();
.......
}

and then

if (_restaurants.isNotEmpty) {
 print('_restaurants: ${_restaurants[0].imageUrl}');
}
notifyListeners();

and two important things:

This construction is bad

  • .try
  • --.then
  • ---.then .then .then

I believe it is necessary to split the methods to request data from FireStore, like that

  • try
  • -- await fetch restaurants
  • catch restaurants loading error
  • try
  • -- await fetch restaurant items
  • catch restaurants items loading error

Hope it helps :)

Upvotes: 2

Related Questions