my nested collections looks like this:
User--> drugs--> drugsTime
I want to update data in document in the subsub-collection (drugsTime)
however I dont know the drug document id and the drugtime document id
so I did the following :
ConfirmDrugTaken(DateTime d) async {
final User? user = FirebaseAuth.instance.currentUser;
final _uid = user?.uid;
var drugID="";
// Get the user's sub-collections in Firestore
final QuerySnapshot<Map<String, dynamic>> querySnapshot =
await FirebaseFirestore.instance
.collection("users")
.doc(_uid)
.collection('drug').where("drugName", isEqualTo: widget.title)
.get();
querySnapshot.docs.forEach((element) async {
drugID=element.id;
});
final QuerySnapshot<Map<String, dynamic>> querySnapshot2 =FirebaseFirestore.instance
.collection("users")
.doc(_uid)
.collection("drug")
.doc(drugID).collection("drugDates").where('time',isEqualTo: d).get() as QuerySnapshot<Map<String, dynamic>>;
querySnapshot2.docs.forEach((element) async {
FirebaseFirestore.instance
.collection("users")
.doc(_uid)
.collection("drug")
.doc(drugID).collection("drugDates").doc(element.id).update( {'isTaken': true});
});
}
but this error occur:
[ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: type 'Future<QuerySnapshot<Map<String, dynamic>>>' is not a subtype of type 'QuerySnapshot<Map<String, dynamic>>' in type cast
E/flutter (17976): #0 _drugSetupState.ConfirmDrugTaken (package:taafi_application_v1/pages/drug_setup.dart:215:79)
E/flutter (17976): <asynchronous suspension>
E/flutter (17976): #1 _drugSetupState.setAlarm.<anonymous closure>.<anonymous closure>.<anonymous closure>.<anonymous closure> (package:taafi_application_v1/pages/drug_setup.dart:112:20)
E/flutter (17976): <asynchronous suspension>
Is there is another way to enter to the sub-sub-collection with out knowing the id OR how can I fix this error?
please help
You forgot to use await to call async method, code should be as follows for querySnapshot2
final QuerySnapshot<Map<String, dynamic>> querySnapshot2 = (await FirebaseFirestore.instance
.collection("users")
.doc(_uid)
.collection("drug")
.doc(drugID).collection("drugDates").where('time',isEqualTo: d).get()) as QuerySnapshot<Map<String, dynamic>>;
Related
I am working on a flutter project where I have two databases, firestore database as online database and sqflite database as localdatabase.
What I am trying to do is that when the user starts the application, it will get a collection of recipes from firestore database and store it locally in sqflite database.
Here is the function:
Future<List> getRecipeDataList() async {
List recipes = [];
int count = await getRecipeCount();
int recipeID = 101;
for (int i = 0; i < count; i++, recipeID++) {
if (await checkIfRecipeDocExists(recipeID.toString()) ==
true) {
QuerySnapshot<Map<String, dynamic>> recipesSnapshot = await FirebaseFirestore.instance.collection('recipes').get();
for(QueryDocumentSnapshot<Map<String, dynamic>> doc in recipesSnapshot.docs){
final data = doc.data();
await LocalDatabase.instance.insertRecipe({
LocalDatabase.recipeID: 100,
LocalDatabase.recipe_name: data['recipe_name'],
LocalDatabase.recipe_description: data['recipe_description'],
LocalDatabase.recipeImageURL: data['recipeImageURL'],
LocalDatabase.recipe_rating: data['recipe_rating'],
LocalDatabase.recipe_time: data['recipe_time'],
LocalDatabase.recipe_ingredients: data['recipe_ingredients'],
});
recipes.add(
Recipes(
recipeID: doc.id,
recipeName: data['recipe_name'],
recipeDescription: data['recipe_description'],
recipeURL: data['recipeImageURL'],
recipeRating: data['recipe_rating'],
recipeTime: data['recipe_time'],
recipeIngredients: (data['recipe_ingredients'] as List<dynamic>).cast<String>(),
),
);
}
}
}
return recipes;
}
This is my sqflite database class:
import 'dart:io';
import 'package:path/path.dart';
import 'package:path_provider/path_provider.dart';
import 'package:sqflite/sqflite.dart';
class LocalDatabase {
//variables
static const dbName = 'localDatabase.db';
static const dbVersion = 1;
static const recipeTable = 'recipes';
static const recipe_description = 'recipe_description';
static const recipe_rating = 'recipe_rating';
static const recipeImageURL = 'recipeImageURL';
static const recipe_time = 'recipe_time';
static const recipe_ingredients = 'recipe_ingredients';
static const recipe_name = 'recipe_name';
static const recipeID = 'recipeID';
static const recipe_category = 'recipe_category';
//Constructor
static final LocalDatabase instance = LocalDatabase();
//Initialize Database
static Database? _database;
Future<Database?> get database async {
_database ??= await initDB();
return _database;
}
initDB() async {
Directory directory = await getApplicationDocumentsDirectory();
String path = join(directory.path, dbName);
return await openDatabase(path, version: dbVersion, onCreate: onCreate);
}
Future onCreate(Database db, int version) async {
db.execute('''
CREATE TABLE $recipeTable (
$recipeID INTEGER,
$recipe_name TEXT,
$recipe_description TEXT,
$recipe_ingredients TEXT,
$recipeImageURL TEXT,
$recipe_category TEXT,
$recipe_time TEXT,
$recipe_rating TEXT,
)
''');
}
insertRecipe(Map<String, dynamic> row) async {
Database? db = await instance.database;
return await db!.insert(recipeTable, row);
}
Future<List<Map<String, dynamic>>> readRecipe() async {
Database? db = await instance.database;
return await db!.query(recipeTable);
}
Future<int> updateRecipe(Map<String, dynamic> row) async {
Database? db = await instance.database;
int id = row[recipeID];
return await db!
.update(recipeTable, row, where: '$recipeID = ?', whereArgs: [id]);
}
Future<int> deleteRecipe(int id) async {
Database? db = await instance.database;
return await db!.delete(recipeTable, where: 'recipeID = ?', whereArgs: [id]);
}
}
Error I am getting is:
I/flutter (13393): *** WARNING *** I/flutter (13393): I/flutter
(13393): Invalid argument [Ingredients 1, Ingredients 2, Ingredients
3] with type List. I/flutter (13393): Only num, String and
Uint8List are supported. See
https://github.com/tekartik/sqflite/blob/master/sqflite/doc/supported_types.md
for details I/flutter (13393): I/flutter (13393): This will throw an
exception in the future. For now it is displayed once per type.
I/flutter (13393): I/flutter (13393): E/flutter (13393):
[ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled
Exception: DatabaseException(java.lang.String cannot be cast to
java.lang.Integer) sql 'INSERT INTO recipes (recipeID, recipe_name,
recipe_description, recipeImageURL, recipe_rating, recipe_time,
recipe_ingredients) VALUES (?, ?, ?, ?, ?, ?, ?)' args [100,
recipe_name, recipe_description, recipeImageURL, recipe_rating,
recipe_time, [Ingredients 1, Ingredients 2, Ingredients 3]] E/flutter
(13393): #0 wrapDatabaseException
(package:sqflite/src/exception_impl.dart:11:7) E/flutter (13393):
E/flutter (13393): #1
SqfliteDatabaseMixin.txnRawInsert.
(package:sqflite_common/src/database_mixin.dart:548:14) E/flutter
(13393): E/flutter (13393): #2
BasicLock.synchronized
(package:synchronized/src/basic_lock.dart:33:16) E/flutter (13393):
E/flutter (13393): #3
SqfliteDatabaseMixin.txnSynchronized
(package:sqflite_common/src/database_mixin.dart:489:14) E/flutter
(13393): E/flutter (13393): #4
LocalDatabase.insertRecipe
(package:recipedia/WidgetsAndUtils/local_database.dart:56:12)
E/flutter (13393): E/flutter (13393): #5
RecipeModel.getRecipeDataList
(package:recipedia/WidgetsAndUtils/recipe_model.dart:78:11) E/flutter
(13393): E/flutter (13393): #6
_LoginState.getRecipeData (package:recipedia/RegistrationAndLogin/login.dart:194:15) E/flutter
(13393): E/flutter (13393):
After reading this error, the problems I can identify is that the recipe_ingredient in firestore database is an array and sqflite doesn't support it. How can I resolve this issue?
If you follow the link reported in the log: https://github.com/tekartik/sqflite/blob/master/sqflite/doc/supported_types.md
it will give you some solutions.
One solution would be to encode the recipe_ingredient list from Firestore as a json string that you save in SQLite.
i.e.
instead of
recipeIngredients: (data['recipe_ingredients'] as List<dynamic>).cast<String>(),
try (well maybe you should handle the null value too):
recipeIngredients: jsonEncode(data['recipe_ingredients'])
I am working on a flutter project where I have two databases firestore database as online database and sqflite database as localdatabase.
what I am trying to do is that when user starts the application, it wil get collection of recipes from firestore database and store it locally in sqflite database.
Here is the function:
Future<List> getRecipeDataList() async {
List recipes = [];
int count = await getRecipeCount();
int recipeID = 101;
for (int i = 0; i < count; i++, recipeID++) {
if (await checkIfRecipeDocExists(recipeID.toString()) ==
true) {
QuerySnapshot<Map<String, dynamic>> recipesSnapshot = await FirebaseFirestore.instance.collection('recipes').get();
for(QueryDocumentSnapshot<Map<String, dynamic>> doc in recipesSnapshot.docs){
final data = doc.data();
await LocalDatabase.instance.insertRecipe({
LocalDatabase.recipeID: 100,
LocalDatabase.recipe_name: data['recipe_name'],
LocalDatabase.recipe_description: data['recipe_description'],
LocalDatabase.recipeImageURL: data['recipeImageURL'],
LocalDatabase.recipe_rating: data['recipe_rating'],
LocalDatabase.recipe_time: data['recipe_time'],
LocalDatabase.recipe_ingredients: data['recipe_ingredients'],
});
recipes.add(
Recipes(
recipeID: doc.id,
recipeName: data['recipe_name'],
recipeDescription: data['recipe_description'],
recipeURL: data['recipeImageURL'],
recipeRating: data['recipe_rating'],
recipeTime: data['recipe_time'],
recipeIngredients: (data['recipe_ingredients'] as List<dynamic>).cast<String>(),
),
);
}
}
}
return recipes;
}
This is my sqflite database class:
import 'dart:io';
import 'package:path/path.dart';
import 'package:path_provider/path_provider.dart';
import 'package:sqflite/sqflite.dart';
class LocalDatabase {
//variables
static const dbName = 'localDatabase.db';
static const dbVersion = 1;
static const recipeTable = 'recipes';
static const recipe_description = 'recipe_description';
static const recipe_rating = 'recipe_rating';
static const recipeImageURL = 'recipeImageURL';
static const recipe_time = 'recipe_time';
static const recipe_ingredients = 'recipe_ingredients';
static const recipe_name = 'recipe_name';
static const recipeID = 'recipeID';
static const recipe_category = 'recipe_category';
//Constructor
static final LocalDatabase instance = LocalDatabase();
//Initialize Database
static Database? _database;
Future<Database?> get database async {
_database ??= await initDB();
return _database;
}
initDB() async {
Directory directory = await getApplicationDocumentsDirectory();
String path = join(directory.path, dbName);
return await openDatabase(path, version: dbVersion, onCreate: onCreate);
}
Future onCreate(Database db, int version) async {
db.execute('''
CREATE TABLE $recipeTable (
$recipeID INTEGER,
$recipe_name TEXT,
$recipe_description TEXT,
$recipe_ingredients TEXT,
$recipeImageURL TEXT,
$recipe_category TEXT,
$recipe_time TEXT,
$recipe_rating TEXT,
)
''');
}
insertRecipe(Map<String, dynamic> row) async {
Database? db = await instance.database;
return await db!.insert(recipeTable, row);
}
Future<List<Map<String, dynamic>>> readRecipe() async {
Database? db = await instance.database;
return await db!.query(recipeTable);
}
Future<int> updateRecipe(Map<String, dynamic> row) async {
Database? db = await instance.database;
int id = row[recipeID];
return await db!
.update(recipeTable, row, where: '$recipeID = ?', whereArgs: [id]);
}
Future<int> deleteRecipe(int id) async {
Database? db = await instance.database;
return await db!.delete(recipeTable, where: 'recipeID = ?', whereArgs: [id]);
}
}
Error I am getting is:
I/flutter (13393): *** WARNING *** I/flutter (13393): I/flutter
(13393): Invalid argument [Ingredients 1, Ingredients 2, Ingredients
3] with type List. I/flutter (13393): Only num, String and
Uint8List are supported. See
https://github.com/tekartik/sqflite/blob/master/sqflite/doc/supported_types.md
for details I/flutter (13393): I/flutter (13393): This will throw an
exception in the future. For now it is displayed once per type.
I/flutter (13393): I/flutter (13393): E/flutter (13393):
[ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled
Exception: DatabaseException(java.lang.String cannot be cast to
java.lang.Integer) sql 'INSERT INTO recipes (recipeID, recipe_name,
recipe_description, recipeImageURL, recipe_rating, recipe_time,
recipe_ingredients) VALUES (?, ?, ?, ?, ?, ?, ?)' args [100,
recipe_name, recipe_description, recipeImageURL, recipe_rating,
recipe_time, [Ingredients 1, Ingredients 2, Ingredients 3]] E/flutter
(13393): #0 wrapDatabaseException
(package:sqflite/src/exception_impl.dart:11:7) E/flutter (13393):
E/flutter (13393): #1
SqfliteDatabaseMixin.txnRawInsert.
(package:sqflite_common/src/database_mixin.dart:548:14) E/flutter
(13393): E/flutter (13393): #2
BasicLock.synchronized
(package:synchronized/src/basic_lock.dart:33:16) E/flutter (13393):
E/flutter (13393): #3
SqfliteDatabaseMixin.txnSynchronized
(package:sqflite_common/src/database_mixin.dart:489:14) E/flutter
(13393): E/flutter (13393): #4
LocalDatabase.insertRecipe
(package:recipedia/WidgetsAndUtils/local_database.dart:56:12)
E/flutter (13393): E/flutter (13393): #5
RecipeModel.getRecipeDataList
(package:recipedia/WidgetsAndUtils/recipe_model.dart:78:11) E/flutter
(13393): E/flutter (13393): #6
_LoginState.getRecipeData (package:recipedia/RegistrationAndLogin/login.dart:194:15) E/flutter
(13393): E/flutter (13393):
After reading this error the problems I can identify is that:
The recipe_ingredient in firestore database is an array and sqflite doesn't support it. How can I resolve this issue?
I appreciate all the input and effort given to solve my problem. Thankyou.
I am building a weather app using OpenWeatherMap API.
Whenever I am passing latitude and longitude then I am getting the data correctly:
Future<dynamic> getWeatherData(double latitude, double longitude) async{
Network network = Network();
var weatherData = await network.getJson("https://api.openweathermap.org/data/2.5/weather?lat=$latitude&lon=$longitude&appid=$APP_ID&units=metric");
return weatherData;
}
I am using weatherData like this:
void updateWeather(dynamic weatherData){
Weather weather = Weather();
setState(() {
if (weatherData == null){
temperature = 0;
temperatureIcon = "💔";
temperatureText = "Can't find weather, make sure GPS is on";
return;
}
temperature = weatherData["main"]["temp"];
int condition = weatherData["weather"][0]["id"];
temperatureIcon = weather.getWeatherIcon(condition);
temperatureText = weather.getMessage(temperature);
});
I am using temperatureIcon and temperatureText in Text() widgets below.
Now I was adding the feature to get weather by searching city name:
var cityName = await Navigator.push(context, MaterialPageRoute(
builder: (context){
return Search();
}
));
if (cityName != null && cityName.toString().isNotEmpty){
Weather weather = Weather();
var weatherData = weather.getWeatherDataCity(cityName);
updateWeather(weatherData);
}
getWeatherDataCity():
Future<dynamic> getWeatherDataCity(String cityName) async{
Network network = Network();
var weatherData = await network.getJson("https://api.openweathermap.org/data/2.5/weather?q=$cityName&appid=$APP_ID&units=metric");
return weatherData;
}
but when I run this code I get this exception:
E/flutter ( 3250): [ERROR:flutter/lib/ui/ui_dart_state.cc(199)] Unhandled Exception: NoSuchMethodError: Class 'Future<dynamic>' has no instance method '[]'.
E/flutter ( 3250): Receiver: Instance of 'Future<dynamic>'
E/flutter ( 3250): Tried calling: []("main")
E/flutter ( 3250): #0 Object.noSuchMethod (dart:core-patch/object_patch.dart:54:5)
E/flutter ( 3250): #1 WeatherScreenState.updateWeather.<anonymous closure> (package:clima/screens/weather_screen.dart:39:32)
E/flutter ( 3250): #2 State.setState (package:flutter/src/widgets/framework.dart:1088:30)
E/flutter ( 3250): #3 WeatherScreenState.updateWeather (package:clima/screens/weather_screen.dart:32:5)
E/flutter ( 3250): #4 WeatherScreenState.build.<anonymous closure> (package:clima/screens/weather_screen.dart:86:25)
E/flutter ( 3250): <asynchronous suspension>
Why am I getting this exception?
The JSON data received is the same when I put city name or latitude and longitude.
Network.getJson():
class Network{
Future<dynamic> getJson(String url) async{
Response response = await get(Uri.parse(url));
print(response.body);
return response.statusCode >= 200 ? jsonDecode(response.body) : null;
}
}
Try awaiting for this function:
var weatherData = await weather.getWeatherDataCity(cityName);
Life would also be a lot easier and code would make more sense if you eliminated all the dynamic and var and used objects.
I am calling the database helper class from ui when I got data from api and that data I have to dump in database to use it offline in the application. I am getting this error. Where am I getting this error and why database is not initialized and allowing me to perform actions on it.
Error:
I/flutter ( 5420): NoSuchMethodError: The method 'insert' was called on null.
I/flutter ( 5420): Receiver: null
I/flutter ( 5420): Tried calling: insert("Deliveries", _LinkedHashMap len:6, conflictAlgorithm: Instance of 'ConflictAlgorithm')
E/flutter ( 5420): [ERROR:flutter/lib/ui/ui_dart_state.cc(157)] Unhandled Exception: NoSuchMethodError: The method 'query' was called on null.
E/flutter ( 5420): Receiver: null
E/flutter ( 5420): Tried calling: query("Deliveries")
E/flutter ( 5420): #0 Object.noSuchMethod (dart:core-patch/object_patch.dart:53:5)
E/flutter ( 5420): #1 TodoHelper.getAllTask (package:delivery_app_odoo_flutter/utils/db_todays_deliveries_model.dart:110:55)
E/flutter ( 5420): #2 _TodayDeliveriesState.inertInDb (package:delivery_app_odoo_flutter/ui/deliveries_page/today_deliveries_page.dart:49:22)
E/flutter ( 5420): <asynchronous suspension>
E/flutter ( 5420): #3 SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1102:15)
E/flutter ( 5420): #4 SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1049:9)
E/flutter ( 5420): #5 SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:957:5)
E/flutter ( 5420): #6 _rootRun (dart:async/zone.dart:1126:13)
E/flutter ( 5420): #7 _CustomZone.run (dart:async/zone.dart:1023:19)
E/flutter ( 5420): #8 _CustomZone.runGuarded (dart:async/zone.dart:925:7)
E/flutter ( 5420): #9 _invoke (dart:ui/hooks.dart:259:10)
E/flutter ( 5420): #10 _drawFrame (dart:ui/hooks.dart:217:3)
E/flutter ( 5420):
Model:
The conversion logic is correct for the allitems in toMap method?. Because we have to convert it into string for storing into local database.
class TodayDeliveriesModel extends Equatable{
String address;
String CustomerName;
String orderNumber;
String total;
List<ItemsModel> allItems;
bool pending;
TodayDeliveriesModel({this.address, this.CustomerName,this.orderNumber, this.allItems, this.total, this.pending});
Map<String, dynamic> toMap(){
return {
Column_address : this.address,
Column_CustomerName:this.CustomerName,
Column_orderNumber:this.orderNumber,
Column_total:this.total,
Column_allItems:this.allItems?.map((e) =>
e == null ? null : ItemsModel(quantity: e.quantity,name: e.name))
?.toList(),
Column_pending:this.pending
};
}
#override
List<TodayDeliveriesModel> get props => deliveriesList;
}
Calling from UI (stateful widget):
#override
void initState() {
// TODO: implement initState
super.initState();
TodoHelper.dba.initDatabase();
todayDeliveries=TodayDeliveriesModel();
listProp = todayDeliveries.props;
// todoHelper=TodoHelper();
insertDataInDB();
}
insertDataInDB()async{
await TodoHelper.dba.insertTask(listProp);
WidgetsBinding.instance.addPostFrameCallback(getFromDb);
}
void getFromDb(Duration timeStamp) async{
await TodoHelper.dba.getAllTask().then((val){
setState(() {
val.forEach((v){
dbList.add(v);
});
});
});
}
Database helper class:
class TodoHelper{
Database _db;
TodoHelper._();
static final TodoHelper dba = TodoHelper._();
Future<Database> get database async {
if (_db != null) return _db;
// if _database is null we instantiate it
_db = await initDatabase();
return _db;
}
Future initDatabase() async{
return await openDatabase(
join(await getDatabasesPath(), "test.db"),
onCreate: (db, version)async{
// return _createDb(db);
await db.execute("CREATE TABLE $tableName($Column_id INTEGER PRIMARY KEY AUTOINCREMENT, $Column_address TEXT, $Column_CustomerName TEXT, $Column_orderNumber TEXT, $Column_total TEXT,$Column_allItems TEXT,$Column_pending TEXT)");
},
version: 1
);
}
Future<void> insertTask(List<TodayDeliveriesModel> task) async{
final Database = await _db;
try{
task.forEach((val){
Database.insert(tableName, val.toMap(), conflictAlgorithm: ConflictAlgorithm.replace);
});
}catch(_){
print(_);
}
}
Future<List<TodayDeliveriesModel>> getAllTask () async{
final List<Map<String, dynamic>> tasks = await _db.query(tableName);
return List.generate(tasks.length, (i){
return TodayDeliveriesModel(address: tasks[i][Column_address],total: tasks[i][Column_total],allItems: tasks[i][Column_allItems],
CustomerName:tasks[i][Column_CustomerName] ,orderNumber: tasks[i][Column_orderNumber],pending: tasks[i][Column_pending] );
});
}
}
initDatabase() is async but in ToDoHelper it isn't being waited for. The issue you have here is that initDatabase() is in the constructor which cannot be async or use await. I have a similar class to handle my apps db which waits for the DB to be required, then either opens the database and saves it to a _db variable or returns the _db variable if the database has previously been opened. This works because it ensures the correct futures have returned before trying to access the database.
If you remove initDatabase() from the constructor and replace Database db; with the following private variable and async getter, the database should work as expected.
static Database _db;
// If there is no database in place then initialise one
Future<Database> get db async {
if (_db != null) {
return _db;
}
// Initialise db
_db = await initDatabase();
return _db;
}
You'll also to make sure you always do await db instead of just db. So in the above example the code around db.insert(...) could become
final database = await db;
task.forEach((val){
database.insert(tableName, val.toMap(), conflictAlgorithm: ConflictAlgorithm.replace);
});
I have a problem with my code. Everything worked before but now im getting this error. I think it is a very little mistake, but I cant see it? I'm very new in flutter and have not so much knowledge. From now on i am doing a video course. Can anybody help me?
Thank you!
Error-Message:
#0 Products.fetchAndSetProducts.<anonymous closure> (package:shop_app_flutter/providers/products.dart:83:26)
#1 __InternalLinkedHashMap&_HashVMBase&MapMixin&_LinkedHashMapMixin.forEach (dart:collection-patch/compact_hash.dart:367:8)
#2 Products.fetchAndSetProducts (package:shop_app_flutter/providers/products.dart:80:21)
<asynchronous suspension>
#3 _ProductsOverviewScreenState.didChangeDependencies (package:shop_app_flutter/screens/products_overview_screen.dart:41:38)
#4 StatefulElement._firstBuild (package:flutter/src/widgets/framework.dart:3862:12)
#5 ComponentElement.mount (package:flutter/src/widgets/framework.dart:3717:5)
#6 Element.inflateWidget (package:flutter/src/widgets/framework.dart:2961:14)
#7 Element.updateChild (package:flutter/src/widgets/framework.dart:2764:12)
#8 SingleChildRenderObjectElement.mount (package:flutter/src/widgets/f<…>
products.dart:
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import '../models/http_exception.dart';
import './product.dart';
class Products with ChangeNotifier {
List<Product> _items = [];
List<Product> get items {
return [..._items];
}
List<Product> get favoriteItems {
return _items.where((prodItem) => prodItem.isFavorite).toList();
}
Product findById(String id) {
return _items.firstWhere((prod) => prod.id == id);
}
Future<void> fetchAndSetProducts() async {
const url = 'https://flutter-update.firebaseio.com/products.json';
try {
final response = await http.get(url);
final extractedData = json.decode(response.body) as Map<String, dynamic>;
if (extractedData == null) {
return;
}
final List<Product> loadedProducts = [];
extractedData.forEach((prodId, prodData) {
loadedProducts.add(Product(
id: prodId,
title: prodData['title'],
description: prodData['description'],
price: prodData['price'],
isFavorite: prodData['isFavorite'],
imageUrl: prodData['imageUrl'],
));
});
_items = loadedProducts;
notifyListeners();
} catch (error) {
throw (error);
}
}
}