Reputation: 198
Error: The method 'data' isn't defined for the class 'Object?'.
- 'Object' is from 'dart:core'.
Try correcting the name to the name of an existing method, or defining a method named 'data'.
Map _productMap = productSnap.data.data();
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:your_store/screens/product_page.dart';
import 'package:your_store/services/firebase_services.dart';
import 'package:your_store/widgets/custom_action_bar.dart';
class SavedTab extends StatelessWidget {
final FirebaseServices _firebaseServices = FirebaseServices();
@override
Widget build(BuildContext context) {
return Container(
child: Stack(
children: [
FutureBuilder<QuerySnapshot>(
future: _firebaseServices.usersRef
.doc(_firebaseServices.getUserId())
.collection("Saved")
.get(),
builder: (context, snapshot) {
if (snapshot.hasError) {
return Scaffold(
body: Center(
child: Text("Error: ${snapshot.error}"),
),
);
}
// Collection Data ready to display
if (snapshot.connectionState == ConnectionState.done) {
// Display the data inside a list view
return ListView(
padding: EdgeInsets.only(
top: 108.0,
bottom: 12.0,
),
children: snapshot.data!.docs.map((document) {
return GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ProductPage(
productId: document.id,
),
));
},
child: FutureBuilder(
future:
_firebaseServices.productRef.doc(document.id).get(),
builder: (context, productSnap) {
if (productSnap.hasError) {
return Container(
child: Center(
child: Text("${productSnap.error}"),
),
);
}
if (productSnap.connectionState ==
ConnectionState.done) {
Map _productMap = productSnap.data.data();
return Padding(
padding: const EdgeInsets.symmetric(
vertical: 16.0,
horizontal: 24.0,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Container(
width: 90,
height: 90,
child: ClipRRect(
borderRadius: BorderRadius.circular(8.0),
child: Image.network(
"${_productMap['images'][0]}",
fit: BoxFit.cover,
),
),
),
Container(
padding: EdgeInsets.only(
left: 16.0,
),
child: Column(
mainAxisAlignment:
MainAxisAlignment.start,
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
"${_productMap['name']}",
style: TextStyle(
fontSize: 18.0,
color: Colors.black,
fontWeight: FontWeight.w600),
),
Padding(
padding: const EdgeInsets.symmetric(
vertical: 4.0,
),
child: Text(
"\$${_productMap['price']}",
style: TextStyle(
fontSize: 16.0,
color: Theme.of(context)
.accentColor,
fontWeight: FontWeight.w600),
),
),
Text(
"Size - ${document['size']}",
style: TextStyle(
fontSize: 16.0,
color: Colors.black,
fontWeight: FontWeight.w600),
),
],
),
),
],
),
);
}
return Container(
child: Center(
child: CircularProgressIndicator(),
),
);
},
),
);
}).toList(),
);
}
// Loading State
return Scaffold(
body: Center(
child: CircularProgressIndicator(),
),
);
},
),
CustomActionBar(
title: "Saved",
hasBackArrow: false,
),
],
),
);
}
}
Upvotes: 0
Views: 1807
Reputation: 31
builder: (context, snapshot) {
if (snapshot.hasError) {
return Scaffold(
body: Center(
child: Text("Error: ${snapshot.error}"),
),
);
}
Convert the snapshot to AsyncSnapshot
snapshot to solve this error. This works for me.
Upvotes: 0
Reputation: 31219
There are multiple problems in your code (taken from your GitHub repo.). I will try list all the problems here with some explanation about each. A common theme are a misunderstanding of using generics so I will recommend you to read about them:
https://dart.dev/guides/language/language-tour#generics
I will highly recommend you are trying to be as specific as possible with all your types in your code since a lot of the current behavior are making use of dynamic
which is not really needed. By making the code more statically type safe, you can also get the compiler to find a lot of errors which is otherwise going to be runtime crashes.
The following found problems is not a full list since most of your problems has the same underlying problem as one of these.
In firebase_services.dart
you has this:
final CollectionReference productRef =
FirebaseFirestore.instance.collection("Products");
final CollectionReference usersRef =
FirebaseFirestore.instance.collection("Users");
This is not correct since you are removing the generic type from CollectionReference
so it becomes CollectionReference<dynamic>
. If you read the return type of .collection
in both cases you will see the returned type is CollectionReference<Map<String, dynamic>>
.
This is important since this type is used when calling methods on the CollectionReference
object other places in your program.
So this should be changed to:
final CollectionReference<Map<String, dynamic>> productRef =
FirebaseFirestore.instance.collection("Products");
final CollectionReference<Map<String, dynamic>> usersRef =
FirebaseFirestore.instance.collection("Users");
FutureBuilder
In cart_page.dart
you have a line 52 the following:
child: FutureBuilder(
future:
_firebaseServices.productRef.doc(document.id).get(),
builder: (context, productSnap) {
If you check the resolved type of productSnap
you can see Dart thinks this has the type AsyncSnapshot<Object?>
which is not that specific. If you look at the documentation for FutureBuilder
it shows you should use this with a generic type which tells what type you expect the Future
to return:
https://api.flutter.dev/flutter/widgets/FutureBuilder-class.html
So change the definition of FutureBuilder
to:
child: FutureBuilder<DocumentSnapshot<Map<String, dynamic>>>(
Another example is in the same file at line 20 with:
FutureBuilder<QuerySnapshot>(
future: _firebaseServices.usersRef
.doc(_firebaseServices.getUserId())
.collection("Cart")
.get(),
builder: (context, snapshot) {
Here, you have QuerySnapshot
but forgets that it also takes generic arguments. So based on the returned value from the future
segment this should really be:
FutureBuilder<QuerySnapshot<Map<String, dynamic>>>(
With our more specific types in the code we come to this error (still in cart_page.dart
) which gives us an error:
if (productSnap.connectionState ==
ConnectionState.done) {
Map _productMap = productSnap.data.data();
A value of type 'Map<String, dynamic>?' can't be assigned to a variable of type 'Map<dynamic, dynamic>'.
The problem here is that by writing Map
you are actually writing Map<dynamic, dynamic>
which will remove important type information. I will recommend just using var
or final
and let Dart automatically assign the best possible type for the variable:
final _productMap = productSnap.data.data();
null
valueLet's continue with the exact same line. Now we gets the following error:
The method 'data' can't be unconditionally invoked because the receiver can be 'null'.
The problem is that the data
property can be null
in case of an error has happen. I don't know how you want to handle this so for now, I am just going to ignore the problem and uses !
to force a runtime null-check to be added:
final _productMap = productSnap.data!.data();
But this is not enough since the output from data()
can also be null
which your code are not handling. Again, I don't know how you want to handle empty data so I am just ignoring the problem:
final _productMap = productSnap.data!.data()!;
ProductSize
constructorInside product_page.dart
you have at line 114 the following:
ProductSize(
productSize: productSize,
onSelected: (size){
_selectedProductSize = size;
},
),
Your ProductSize
constructor is:
final List? productSize;
final String? onSelected;
ProductSize({this.productSize, this.onSelected});
So you are trying to assign a method to onSelected
which takes a String?
as argument. I don't know what you are trying to do here but the current code does not make any sense.
Upvotes: 1