Closure: () => Map<String, dynamic> from Function 'data': - firebase

So im trying to stream data from firestore but when printing the data I get:
I/flutter ( 8356): Closure: () => Map<String, dynamic> from Function 'data':.
I am using this code to fetch the data:
void messagesStream() async {
Stream collectionStream = _firestore.collection('messages').snapshots();
await for (var snapshot in collectionStream) {
for (var message in snapshot.docs) {
print(message.data());
}
}
When new data is added to the messages collection I get the Closure message so it is interacting with the databse.
What I want is it to print out the contents of the new document within the collection.
Any help is appreciated.

That's not the way you're supposed to iterate the results of a Stream. If you have a Stream and you want to process its results, you're supposed to use listen() to receive the results asynchronously.
Stream collectionStream = _firestore.collection('messages').snapshots();
collectionStream.listen((QuerySnapshot querySnapshot) {
querySnapshot.documents.forEach((document) => print(document.data()));
}
See also: Firestore collection query as stream in flutter
You might also want to review the documentation to learn how to query Firestore in Flutter.

void getMessages() async {
final messages= await _firestore.collection('messages').get();
for(var message in messages.docs){
print(message.data());
}
this is working check this and call getMessages() wherever you wana call

I encountered the same issue with pretty much your exact same code (sans your Stream variable). My suggestion is to delete the Stream var altogether (I tested the code below and got it to print the data from the Firestore database) :
void messagesStream() async {
await for (var snapshot in _firestore.collection('messages').snapshots()) {
for (var message in snapshot.docs) {
print(message.data());
}
}
}
Alternatively, try addding QuerySnapShot as the data type for your Stream variable (untested):
Stream<QuerySnapshot> collectionStream = _firestore.collection('messages').snapshots();
You could also replace the entire method by creating a new Stateless Widget (MessagesStream) that returns a StreamBuilder:
class MessagesStream extends StatelessWidget {
#override
Widget build(BuildContext context) {
return StreamBuilder<QuerySnapshot>(
stream: _firestore.collection('messages').snapshots(),
builder: (context, snapshot) {
final messages = snapshot.data.docs;
for (var message in messages) {
print(message.data());
}
...and call it wherever you see fit while you test:
class _ChatScreenState extends State<ChatScreen> { (...)
body: Column(children: <Widget> [
//Just an example.
MessageStream(),
],
),
(...)
}
***Be sure you make the _fireStore (which should be a FirebaseFirestore.instance) a global variable if you're going with the Stateless Widget route.

I received this error while trying to throw a custom error class InkError:
You meed add toMap the class.
final response = await http.post(url, body: body, headers: headers);
final json = jsonDecode(response.body);
if (response.statusCode == HttpStatus.ok) {
return json;
} else {
throw InkError(
code: 0,
message: json['message'],
statusCode: response.statusCode,
).toMap();
InkError
class InkError {
/// Error code.
final int code;
/// Error message.
final String message;
/// HTTP Status Code
final int? statusCode;
const InkError({
required this.code,
required this.message,
this.statusCode,
});
factory InkError.fromJSON(Map<String, dynamic> json) => InkError(
code: json['code'] as int,
message: json['message'] as String,
statusCode: json['statusCode'],
);
Map<String, dynamic> toMap() {
return {
'code': code,
'message': message,
'statusCode': statusCode,
};
}
#override
String toString() {
return toMap().toString();
}
}

Related

How to display all the names in database firestorefirebase flutter

In my app I have a model which consists of the store name and store image and looks like this:
class StoreModel
{
String? imageofStore;
String? storeName;
StoreModel({ this.imageofStore, this.storeName});
//data from server
factory StoreModel.fromMap(map)
{
return StoreModel(
imageofStore: map['imageofStore'],
storeName: map['storeName'],
);
}
// data to server
Map<String, dynamic> toMap(){
return{
'imageofStore': imageofStore,
'storeName': storeName,
};
}
}
and my database for stores looks like this:
to call the store name I use initstate and setState as such:
class addStore extends StatefulWidget {
const addStore({Key? key}) : super(key: key);
#override
_addStoreState createState() => _addStoreState();
}
class _addStoreState extends State<addStore> {
User ? user = FirebaseAuth.instance.currentUser;
StoreModel storebox = StoreModel();
#override
void initState()
{
super.initState();
FirebaseFirestore.instance
.collection("stores")
.doc("XQjbm665g2a2xAiiydjr")
.get()
.then((value){
this.storebox = StoreModel.fromMap(value.data());
setState(() {
});
});
}
#override
Widget build(BuildContext context) {
return Container(
child: Text("${storebox.storeName}"),
);
}
}
With this, I get the store name of the store with id XQjbm665g2a2xAiiydjr displaying but the thing is I want to get the name of all the stores. I know I need to change the .doc() but im not sure as to what I am to put in it that will start displaying all the names. Can someone please help?
By providing a document id, what you're getting is a DocumentSnapshot which is the data of a particular Document, but when you remove it, you get QuerySnapshot which is a list of the data of all the documents. So, to read all, you change your code as:
List<StoreModel> storesList = [];
FirebaseFirestore.instance
.collection("stores")
.get()
.then((value){
//Now, this value is of type QuerySnapshot unlike earlier.
if (value != null && value.docs.isNotEmpty) {
//If it comes here means the collection is not empty.
//Because this value is a list of DocumentSnapshot, We've to map it to extract documents.
//After mapping, returning it as a list and assigning it to storesList
storesList = value.docs.map((doc) => StoreModel.fromMap(doc.data())).toList();
setState(() {
});
} else {
//If it comes here means there are no documents in your collection.
//Notify User there's no data.
}
});
This code will get all the documents your collection have, but, you can limit or filter using limit or where respectively, just place .limit(int) or .where() before .get().
for model try to convert to json or you can use your either way this is just for example model
import 'dart:convert';
List<StoreModel> storeModelFromJson(String str) => List<StoreModel>.from(json.decode(str).map((x) => StoreModel.fromJson(x)));
String storeModelToJson(List<StoreModel> data) => json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
class StoreModel {
StoreModel({
this.imageofStore,
this.storeName,
});
final String? imageofStore;
final String? storeName;
factory StoreModel.fromJson(Map<String, dynamic> json) => StoreModel(
imageofStore: json["imageofStore"] == null ? null : json["imageofStore"]!,
storeName: json["storeName"] == null ? null : json["storeName"]!,
);
Map<String, dynamic> toJson() => {
"imageofStore": imageofStore == null ? null : imageofStore!,
"storeName": storeName == null ? null : storeName!,
};
}
try this get all list
static Future<List<StoreModel>> getStorelist() async {
List<dynamic> list = [];
await FirebaseFirestore.instance
.collection("stores")
.get()
.then((value){
for(var x in value.docs){
final Map<String,dynamic> toMap = x.data() as Map<String,dynamic>;
/// Try to print all data first to see if fetching use log to view on terminal
log(toMap.toString());
list.add(toMap);
}
});
return list.map((e)= > StoreModel.fromJson(e)).toList();
}
as in my case to get only 1 data
static getSingleName(String? uid) async {
final result =
await FirebaseFirestore.instance
.collection("stores").doc(uid).get();
final response = result.data() as Map<String, dynamic>;
return response['storeName'].toString();
}

Unhandled Exception: FormatException: Unexpected character

I couldn't transform my fetched the data,
But no errors showing, I have added a print statement to find error where it occurs
Future<void> fetchAndSetProduct() async {
final url =
Uri.https('shopda-83b00-default-rtdb.firebaseio.com', '/products');
try {
print("karan oneonofne ");
final response = await http.get(url);
final extractData = json.decode(response.body) as Map<String, dynamic>;
final List<Product> loadedProduct = [];
extractData.forEach((prodId, prodData) {
loadedProduct.add(Product(
id: prodId,
title: prodData['title'],
description: prodData['description'],
price: prodData['price'],
isFavourite: prodData['isFavourite'],
imageUrl: prodData['imageUrl']));
});
print(loadedProduct[1]);
_items = loadedProduct;
notifyListeners();
} catch (error) {
throw (error);
} finally {
print('object');
}
}
then I changed like this
Still, I couldn't get data.I think I couldn't change HTML to Jason
You're trying to fetch data from your Realtime Database by using the direct link.
This requires you to sign in and that is the HTML page it returns.
You should use the firebase_database package to fetch the data from the database.
You should update your fetchAndSetProduct method to this:
Future<void> fetchAndSetProduct() async {
try {
...
final DataSnapshot dataSnapshot = await FirebaseDatabase.instance.reference().child('products').once();
final extractData = json.decode(dataSnapshot.value) as Map<String, dynamic>;
...
} catch (error) {
...
} finally {
...
}
}
I found it Please change HTML file Json by simply
final url =
Uri.https('shopda-83b00-default-rtdb.firebaseio.com', '/products.json');

Flutter Firebase A value of type 'List<Future<CustomClass>>' can't be assigned to a variable of type 'List< CustomClass >?'

I am having an issue with my FutureBuilder in flutter. It's supposed to map the custom class 'GeoPost' to a 'List' from a firebase query but somewhere in my code it is not reading the Geopost list as a non Future
here is the code where the error occurs:
FutureBuilder(
future: postsRef.get().then((doc) {
geoPosts = doc.docs.map((doc) async => await GeoPost.fromDoc(doc)).toList();
}),
builder: (context, snapshot) { }
custom class and functions:
class GeoPost {
final String caption;
final String postId;
final String authorId;
final int likesCount;
final int commentCount;
final Position position;
final Timestamp timeStamp;
final String? imageUrl;
final Userdata authordata;
GeoPost(this.caption, this.postId, this.authorId, this.likesCount, this.commentCount, this.position, this.timeStamp, this.imageUrl, this.authordata);
static Future<GeoPost> fromDoc(DocumentSnapshot doc) async {
return GeoPost.fromDocument(doc, await getPostUserDataFromFirestore(doc['userId']));
}
factory GeoPost.fromDocument(DocumentSnapshot doc, Userdata author) {
return GeoPost(
doc['caption'],
doc['postId'],
doc['userId'],
doc['likeCount'] ?? 0,
doc['commentCount'] ?? 0,
doc['position'],
doc['timeStamp'],
doc['imageUrl'],
author
);
}
Future<void> getPostUserDataFromFirestore (String did) async {
return Userdata.fromDoc(await usersRef.doc(uid).get());
}
}
error:
Error: A value of type 'List<Future<GeoPost>>' can't be assigned to a variable of type 'List<GeoPost>?'.
You need to wait for all the Futures in the List<Future<GeoPost> (which converts them into a List<GeoPost>) before assiging them to a variable of type List<GeoPost>.
Update your FutureBuilder code to this:
FutureBuilder<List<GeoPost>>(
future: () async {
var doc = await FirebaseFirestore.instance.collection('collectionPath').get();
var data = doc.docs.map((doc) async => await GeoPost.fromDoc(doc)).toList();
geoPosts = await Future.wait(data);
return geoPosts;
}(),
builder: (context, snapshot) { }
Also, you need to change the return type of the getPostUserDataFromFirestore method from Future<void> to Future<Userdata>. void is used when there is no value returned.
Update the getPostUserDataFromFirestore method to this:
Future<Userdata> getPostUserDataFromFirestore (String did) async {
return Userdata.fromDoc(await usersRef.doc(uid).get());
}

Flutter FutureBuilder returns nothing - Cloud Firestore and Deserialization

I have the following problem. I'm trying to receive data from my Firestore collection called tournaments. I'm querying the database from within my DatabaseService class. That looks like the following:
class Collection<T> {
final Firestore _db = Firestore.instance;
final String path;
CollectionReference ref;
Collection({this.path}) {
ref = _db.collection(path);
}
Future<List<Tournament>> getData() async {
var snapshots = await ref.getDocuments();
return snapshots.documents
.map((doc) => Global.models[Tournament](doc.data))
.toList();
}
}
The widget implements a FutureBuilder
Widget build(BuildContext context) {
return FutureBuilder(
future: Global.tournamentRef.getData(),
builder: (BuildContext context, AsyncSnapshot snap) {
if (snap.connectionState == ConnectionState.done) {
List<Tournament> tournaments = snap.data;
...
I want to deserialize the firestore data into a Tournament object. I defined the Tournament class as this:
class Tournament {
String id;
String name;
String mode;
String owner;
int size;
Tournament({this.id, this.name, this.mode, this.owner, this.size});
factory Tournament.fromMap(Map data) {
return Tournament(
id: data["id"] ?? '',
mode: data["mode"] ?? '',
name: data["name"] ?? "group",
owner: data["owner"] ?? "",
size: data["size"] ?? 6);
}
}
The last class that is important is the globals.dart
class Global {
static final Map models = {Tournament: (data) => Tournament.fromMap(data)};
static final Collection<Tournament> tournamentRef =
Collection<Tournament>(path: "tournaments");
}
It simply specifies the collection path. I want the data to be deserialized but I don't have a clue why it isn't returning anything. I've tried querying the database in a simple old-fashioned way like
Future<dynamic> retrieveData() async {
var querySnap = await ref.getDocuments();
var list = querySnap.documents.map((snap) => snap.data);
return list;
}
That worked perfectly fine, however it doesn't help with deserialization at all. I think i missed something at some point and as you may notice I'm still a Flutter/dart beginner and some of these discussed topics are a bit too complicated to me.
I appreciate any help.
Thank you

Firestore Document error - Only static members can be accessed in initializers

I want to get Products added to cart by user.So i am trying to get documents based on uid(Documents named as uid)
But i am getting error
Only static members can be accessed in initializer
Code:
class CartDataBase{
FirebaseUser user;
final FirebaseAuth _auth=FirebaseAuth.instance;
void getUid()async
{
user=await _auth.currentUser();
}
final CollectionReference cart1 = Firestore.instance.collection('users').document(user.uid)//Only static members can be accessed in initializer
.collection('CartProducts');
List<Checkout> _checkout(QuerySnapshot snapshot) {
return snapshot.documents.map((doc) {
return Checkout(
original: doc.data['original'] ?? 999,
image: doc.data['image'] ?? 'Error',
name: doc.data['name'] ?? 'Error',
quantity: doc.data['Quantity'] ?? 'N/A',
identifier: doc.data['identifier'] ?? 'qwerty',
price: doc.data['price'] ?? 999,
iPP: doc.data['IPP'] ?? 999,
uPQ: doc.data['UPQ'] ?? 999,
);
}).toList();
}
Stream<List<Checkout>> get CartProducts {
return cart1.snapshots().map(_checkout);
}
}
Screenshot for reference
The problem in your code can be found here:
final CollectionReference cart1 = Firestore.instance.collection('users').document(user.uid).collection('CartProducts');
There is no way you can assign that to the variable without waiting for it to finish fetching the document. You have to call await method first before you access it. We can solve this with the await keyword
final CollectionReference cart1 = await Firestore.instance.collection('users').document(user.uid).collection('CartProducts');
Since you cannot call async in your class, you have to convert it into a function as well as call that function in initstate() which gets called before your ui builds.
getDetails() async {
final CollectionReference cart1 = await Firestore.instance.collection('users').document(user.uid).collection('CartProducts');
//other things here
}
//place this below your widget build
#override
void initState() {
getDetails();
super.initState();
}

Resources