The argument type 'ProductModel?' can't be assigned to the parameter type 'ProductModel' - flutter

I'm making a midel to upload product image,price and name to firebase then i face this error (The argument type 'ProductModel?' can't be assigned to the parameter type 'ProductModel'.)
class ProductProvider with ChangeNotifier {
List<ProductModel> pizzaProductList = [];
ProductModel? productModel;
fatchPizzaproductData() async {
// List<ProductModel> newList = [];
QuerySnapshot value =
await FirebaseFirestore.instance.collection("PizzaProducts").get();
pizzaProductList = value.docs.map((element) {
return ProductModel(
productImage: element.get("productImage"),
productName: element.get("productName"),
productPrice: element.get("productPrice"),
);
}).toList();
}
get getPizzaproductDataList {
return pizzaProductList;
}
}

The problem is that productModel is a nullable type, whereas pizzaProduct is a List of non-nullable ProductModels.
Instead of storing a property productModel on your class, consider mapping directly from value.docs to pizzaProduct, and removing the intermediate step of storing the model in productModel:
class ProductProvider with ChangeNotifier {
List<ProductModel> pizzaProduct = [];
Future<void> fetchPizzaProductData() async {
QuerySnapshot value =
await FirebaseFirestore.instance.collection("PizzaProducts").get();
pizzaProduct = value.docs.map((element) {
return ProductModel(
productImage: element.get("productImage"),
productName: element.get("productName"),
productPrice: element.get("productPrice"),
);
}).toList();
// Since this is a ChangeNotifier, I'm assuming you might want to
// notify listeners when `pizzaProduct` changes. Disregard this line
// if that's not the case.
notifyListeners();
}
}

Related

The argument type 'Object?' can't be assigned to the parameter type 'Map<dynamic, dynamic>'. GetX

so basically i'm frustrated by this 'Object?' type, i already tried t change its type in core file but i was worried to cause a weird behavior in the future. heres my code any kind of help will be appreciated
class HomeViewModel extends GetxController{
List<CategoryModel> get categorymodel => _categorymodel;
late DocumentSnapshot doc;
List<CategoryModel> _categorymodel = [];
final CollectionReference _categoryCollectionRef =
FirebaseFirestore.instance.collection('categories');
HomeViewModel(){
getCategory();
}
getCategory()async{
_categoryCollectionRef.get().then((value) {
for(int i = 0; i<value.docs.length;i++){
_categorymodel.add(CategoryModel.fromJson(value.docs[i].data()));
}
});
}
}
and this one is from my model class:
class CategoryModel {
late String name, image;
CategoryModel({required this.name, required this.image});
CategoryModel.fromJson(Map<dynamic, dynamic> map) {
if (map == null) {
return;
}
name = map['name'];
image = map['image'];
}
toJson() {
return {
'name': name,
'image': image,
};
}
}
You need to specify the type of data you're expecting from the DocumentSnapshot.
Change this line:
_categorymodel.add(CategoryModel.fromJson(value.docs[i].data()));
to this:
_categorymodel.add(CategoryModel.fromJson(value.docs[i].data() as Map<String, dynamic>));
Check out the guide for migration to cloud_firestore 2.0.0.

A value of type 'Rx<Future<List<SectionsDBStat>>*>*' can't be assigned to a variable of type

I am learning Flutter and GetX.
I have got Model:
class SectionsDBStat {
int notificationsTotalCount;
int notificationsWaitingForProcessing;
DateTime notificationsLastArchiveDate;
SectionsDBStat({
required this.notificationsTotalCount,
required this.notificationsWaitingForProcessing,
required this.notificationsLastArchiveDate
});
factory SectionsDBStat.fromJson(Map<String, dynamic> json) {
return SectionsDBStat(
notificationsTotalCount: json['notificationsTotalCount'],
notificationsWaitingForProcessing: json['notificationsWaitingForProcessing'],
notificationsLastArchiveDate: DateTime.parse(json['notificationsLastArchiveDate'])
);
}
}
I am trying to create Getx contoller that receive data from http:
class SectionsStatController extends GetxController {
SectionsDBStat sectionsDBStat = Future.value(<SectionsDBStat>).obs;
getStat() async {
var value = await http.get('${url}/stat?total');
if(value.statusCode == 200) {
Map<String, dynamic> valueMap = jsonDecode(value.body)['data'];
sectionsDBStat = SectionsDBStat.fromJson(valueMap);
update();
} else {
print("Can't get stat: ${value.statusCode}");
}
}
}
I am getting an error:
A value of type 'Rx<Future<List<SectionsDBStat>>*>*' can't be assigned to a variable of type 'SectionsDBStat'.
So I should use another type. But what? I tried final but got error:
'sectionsDBStat' can't be used as a setter because it's final.
I don't know why are you using Future, here you are trying to assign Rx<Future<List<SectionsDBStat>>*> to sectionsDBStat and that is not possible
Replace this line
SectionsDBStat sectionsDBStat = Future.value(<SectionsDBStat>).obs;
with this
final sectionsDBStat = SectionsDBStat().obs;
and then assign it like this
sectionsDBStat.value = SectionsDBStat.fromJson(valueMap);

Flutter data serialization and deserialization with firestore db

I ran into this weird error in Flutter. I'm using a custom data model:
class ScanData {
final String userID;
final String companyID;
final String scanID;
final String deviceID;
final String model;
final Map result;
final DateTime dateTime;
final GeoPoint geoPoint;
ScanData(
{this.userID,
this.companyID,
this.scanID,
this.deviceID,
this.model,
this.result,
this.geoPoint,
this.dateTime});
factory ScanData.fromMap(Map data) {
return ScanData(
userID: data['userID'] ?? '',
companyID: data['companyID'] ?? '',
scanID: data['scanID'] ?? '',
deviceID: data['deviceID'] ?? '',
model: data['model'] ?? '',
result: data['result'] ?? {},
dateTime: data['dateTime'] as DateTime ?? DateTime.now(),
geoPoint: data['geoPoint'] as GeoPoint ?? ['77', '28'],
);
}
}
Created a method in Collection class to retrieve data from firestore:
class Collection<T> {
final FirebaseFirestore _db = FirebaseFirestore.instance;
final String path;
CollectionReference ref;
Collection({this.path}) {
ref = _db.collection(path);
}
Future<List<T>> getData() async {
var snapshots = await ref.get();
return snapshots.docs
.map((doc) => Global.models[T](doc.data) as T)
.toList();
}
}
Calling it in widget, this works if I don't use the data model and instead call the collection directly, but it's much easier since I don't want to create it everywhere I go and helps with type checking and intellisense...
FutureBuilder(
future: Collection<ScanData>(path: 'scans').getData(),
builder: (context, AsyncSnapshot<List<ScanData>> snapshot) {
if (!snapshot.hasData || snapshot.hasError) {
return Container(
alignment: Alignment.center,
child: CircularProgressIndicator());
} else {
return _buildScansList(snapshot.data);
}
},
)
Globals:
class Global {
static final Map models = {
ScanData: (data) => ScanData.fromMap(data),
};
}
The error (occurs in Globals fromMap):
Exception has occurred.
_TypeError (type '() => Map<String, dynamic>' is not a subtype of type 'Map<dynamic, dynamic>')
I tried putting the following in the ScanData model
factory ScanData.fromMap(Map<String,dynamic> data) {...}
but this gives another error:
Exception has occurred.
_TypeError (type '() => Map<String, dynamic>' is not a subtype of type 'Map<String, dynamic>')
:| Any tips appreciated.
In the method getData() of Collection class, doc.data is not property, it's a method, so just add ().

Flutter Firestore array with Maps. Do they work?

I can't stream (read) Documents that contain array properties that are Maps in Firestore.
Using Firestore with a document containing an array with a simple String type works as expected. Easy to write (append with FieldValue.arrayUnion(['data1','data2','data3']) and stream back out with code like:
var test2 = List<String>();
for (var item in data['items']) {
print('The item $item');
test2.add(item);
}
test2 can now be used as my items property.
When I try and use a List where item type becomes a Map in Firestore and is just a simple Class containing a few Strings and a date property. I can write these to FireStore but I can't read them back out.
The following code fails: (no errors in the Debug Console but it doesn't run)
var test2 = List<Item>();
data['items'].forEach((item) {
var description = item['description'];
print('The description $description'); // <-- I don't get past this
final x = Item.fromMap(item); // <-- so I can't even attempt this
return test2.add(x);
});
I never get to actually call my Item.fromMap constructor: here is another try:
// fails
final theItems = data['items'].map((x) {
return Item.fromMap(x); // <-- never get here
});
Although the DEBUG CONSOLE doesn't say there is any problem. If I inspect theItems variable (the debugger 'jumps' a couple of lines down to my return) after the failed iteration it looks like this:
MappedListIterable
_f:Closure
_source:List (1 item)
first:Unhandled exception:\ntype '_InternalLinkedHashMap<dynamic, dynamic>' is not a subtype of type 'Map<String, dynamic>'\n#0 new Listing.fromMap.<anonymous closure> isEmpty:false
isNotEmpty:true
iterator:ListIterator
last:Unhandled exception:\ntype '_InternalLinkedHashMap<dynamic, dynamic>' is not a subtype of
So bad things have happened but I have no idea why!
Has anyone actually written and retrieved Firestore array properties that contain Maps?
Any help in how to proceed would be greatly appreciated!
More: screen shot of the document
Here is the code that reads (streams) the collection
Stream<List<T>> collectionStream<T>({
#required String path,
#required T builder(Map<String, dynamic> data, String documentID),
#required String userId,
Query queryBuilder(Query query),
int sort(T lhs, T rhs),
}) {
Query query = Firestore.instance.collection(path);
if (queryBuilder != null) {
query = queryBuilder(query);
}
final Stream<QuerySnapshot> snapshots = query.snapshots();
return snapshots.map((snapshot) {
//print('document: path $path ${snapshot.documents[0]?.documentID}');
final result = snapshot.documents
.map((snapshot) => builder(snapshot.data, snapshot.documentID))
.where((value) => value != null)
.toList();
if (sort != null) {
result.sort(sort);
}
print('returning from CollectionStream');
return result;
});
}
the .map is where the problem comes in. The builder function resolves to this:
builder: (data, documentId) {
return Listing.fromMap(data, documentId);
},
Which ends up here
factory Listing.fromMap(
Map<String, dynamic> data,
String documentId,
) {
if (data == null) {
return null;
}
final theTime = (data['createdAt'] as Timestamp).toDate();
// see above code where I fail at getting at the items property/field
Here is the Item Class:
class Item {
Item(this.description, this.imageURL, this.thumbnailURL,
{this.status = ItemStatus.active,
this.type = ListingType.free,
this.price = 0,
this.isUpdate = false,
this.createdAt});
final String description;
final String imageURL;
final String thumbnailURL;
final ItemStatus status;
final ListingType type;
final int price;
final bool isUpdate;
DateTime createdAt;
factory Item.fromMap(
Map<String, dynamic> data,
) {
if (data == null) {
return null;
}
final theTime = (data['createdAt'] as Timestamp).toDate();
return Item(
data['description'],
data['imageURL'],
data['thumbnailURL'],
status: _itemStatusFromString(data['status']),
type: data['type'] == 'free' ? ListingType.free : ListingType.flatRate,
createdAt: theTime,
);
}
Map<String, dynamic> toMap() {
// enums are for shit in Dart
final statusString = status.toString().split('.')[1];
final typeString = type.toString().split('.')[1];
return {
'description': description,
'imageURL': imageURL,
'thumbnailURL': thumbnailURL,
'itemStatus': statusString,
'price': price,
'listingType': typeString,
if (!isUpdate) 'createdAt': DateTime.now(),
if (isUpdate) 'updatedAt': DateTime.now(),
};
}
}
The above is never called to read (we crash) ... it is called to write the data.
This is a known issue with Firestore. Here is the starting thread Flutter issues I found
From reading through the issues it seems lots of folks use a serializer package which is where the issue surfaced. Its still active...
Here is my solution NOT using a serializer and just doing it 'by hand'.
I was able simplify the problem and generate an error that was Google-able. Below is a single page which just writes and reads a single Document. The Class A and B are as small as can be.
So the code writes a single document to Firestore the contains two properties. A name and items. The items being the List of Class B that Class A contains. Checkout the Firebase console. The reading just does that.
No StreamController just the Console. The problem is in the fromMap method where we have to convert the array of objects in Firesote to a List of class instances in Dart. This should not be this difficult and at a minimum it should be documented ....
the line
var theRealItems = data['items'].map((i) => B.fromMap(i));
will generate the error. And needs to be replaced with
var theItems = data['items'].map((i) {
var z = Map<String, dynamic>.from(i);
print(z['description']);
return B.fromMap(z);
}).toList();
var theRealItems = List<B>.from(theItems);
Why this is so difficult is still a mystery to me! Anyone improving this code: I'm all ears.
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
class A {
A(this.name, this.items);
final name;
final List<B> items;
factory A.fromMap(
Map<String, dynamic> data,
String documentId,
) {
if (data == null) {
return null;
}
// we crash here !!!
var theRealItems = data['items'].map((i) => B.fromMap(i));
// uncomment the 6 lines below
// var theItems = data['items'].map((i) {
// var z = Map<String, dynamic>.from(i);
// print(z['description']);
// return B.fromMap(z);
// }).toList();
// var theRealItems = List<B>.from(theItems);
return A(data['name'], theRealItems);
}
Map<String, dynamic> toMap() {
var theItems = items.map((i) => i.toMap()).toList();
return {'name': name, 'items': theItems};
}
}
class B {
B(this.description);
final description;
factory B.fromMap(
Map<String, dynamic> data,
) {
if (data == null) {
return null;
}
return B(data['description']);
}
Map<String, dynamic> toMap() {
return {
'description': description,
};
}
}
class Test extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
RaisedButton(
onPressed: () => _write(),
child: Text('Write the Doc'),
),
RaisedButton(
onPressed: () => _read(),
child: Text('Read the Doc ... check Debug Console!'),
),
],
),
),
);
}
_write() async {
try {
var b = B('Inside B!');
List<B> theList = List<B>();
theList.add(b);
var a = A('myName', theList);
await Firestore.instance
.collection('test')
.document('testDoc')
.setData(a.toMap());
print('returning from write!');
} catch (e) {
print('Error ${e.toString()}');
}
}
_read() async {
try {
var aFromFs = await Firestore.instance
.collection('test')
.document('testDoc')
.get();
var a = A.fromMap(aFromFs.data, aFromFs.documentID);
print('the A from FireBase $a with name ${a.name} first item ${a.items.first.description}');
print('returning from read!');
} catch (e) {
print('Oh no Error! ${e.toString()}');
}
}
}
In the below code Name refers to the name of your respective document and collection.
Let's say you want to get "imageURL" and "thumbnailUrl" for now and update the values without deleting or changing other fields inside the array.
String imageUrl ;
String thumbnailUrl;
DocumentReference _docReference = FirebaseFirestore.instance.collection(NAME).doc(NAME);
//refering to the specific document
Map<String, dynamic> neededData= allDocsFromTraining.data();
//getting all the keys and values inside the document
List<Map<String, dynamic>> _yourDocument=
(neededData["items"] as List<dynamic>)
.map((m) => Map<String, dynamic>.from(m))
.toList();
//only getting the list of items
for (int index = 0; index < _yourDocument.length; index++) {
Map<String, dynamic> _getMap = _yourDocument[index];
if (_getMap["price"] == 0)
//giving a condition to get the desired value and make changes
{
//setting the variables with the value from the database
setState(() {
imageUrl = _getMap["imageURL"];
thumbnailUrl = _getMap["thumbnailURL"]
});
///Use this if you want to update value of imageURL and thumbnailURL at that specific index of an array
_getMap['imageURL'] = "Your Updated URL";
_getMap['thumbnailURL'] = "Your Updated Url;
break;
} else {}
}
await _docReference.update({"items": _yourDocument});
//this adds the updated value to your database.

type 'int' is not subtype of type 'String' on Flutter

I modified description value to 1 on my database.
List<DataEquipmentReg> values = snapshot.data;
assetArray.add('${values[i].eq_no.toString()} : ${values[i].description.toString()}');
After edit description value to String, Error is not coming
DataEquipmentReg POJO Class
class DataEquipmentReg {
final String eq_no;
final String description;
}
Widget
Text(assetArray[index].toString(),),
Database in sqlite
await db.execute("""CREATE TABLE EquipmentRegTable(eq_no STRING, description STRING)""");
I solved this problem like this,
in my read data on cache method, I changed this,
Future<List<DataEquipmentReg>> displayEquipmentReg() async {
var db = await db1;
final List<Map<String, dynamic>> maps = await db.query('EquipmentRegTable');
return List.generate(maps.length, (i) {
return DataEquipmentReg(
eq_no: '${maps[i]['eq_no']}',
description'${ maps[i]['description']}',
);
});
}