Unhandled Exception: FormatException: Unexpected character - firebase

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');

Related

how to get value from map in firebase database flutter

i have a json structure like this
{
"-My6relBpWvPaY_I4JvN": {
"idUser": "4dca8440-a37d-11ec-9c66-9b8f61be17f0",
"message": "777777"
}
}
and I wanna use fromJson to save to map,
here is my model:
class Message {
final String userId;
final String message;
const Message({
#required this.userId,
#required this.message,
});
static Message fromJson(Map<String, dynamic> json) => Message(
userId: json['idUser'],
message: json['message'],
);
Map<String, dynamic> toJson() => {
'idUser': userId,
'message': message,
};
}
right now I always get null from the help from Frank,
final data = Map<String, dynamic>.from(snapshot.value as Map);
Message message = Message.fromJson(data);
print('message value${message.message}'); // here i got null
please tell me where is wrong.
---------- Update ----------
Hi Frank, firstly thanks for your reply, I will get a stream from firebase RTDB, since the data structure is as displayed above, with the data I got from following method,
final Map<String, dynamic> data = Map<String, dynamic>.from(snapshot.value as Map);
the key from this data will be {"-My6relBpWvPaY_I4JvN"}, and value is
{
"idUser": "4dca8440-a37d-11ec-9c66-9b8f61be17f0",
"message": "777777"
}
so in this case I need to update the method you showed
//**instead** snapshot.children.forEach((msgSnapshot) {
data.values.forEach((msgSnapshot) {
final Map<String, dynamic> messageData = Map<String, dynamic>.from(msgSnapshot as Map);
//i am not sure whether I need to use msgSnapshot.value as Map, since msgSnaphot is already the right Map<String, dynamic> that I can put to fromJson
Message message = Message.fromJson(messageData);
})
Do I understand correctly? thanks for further info!!
I have it setup like this in my case witch works just fine:
static Message model({required Map map}) => Message(
messageID: map[kModelMessengerID],
owner: map[kModelMessageOwner],
type: map[kModelMessageType],
msg: map[kModelMessageMsg],
membersIDs: (map[kModelMessageMembersIDs] as List<dynamic>)
.map((e) => e.toString())
.toList(),
createdAt: map[kModelMessageCreatedAt] == null
? DateTime.now()
: (map[kModelMessageCreatedAt] as Timestamp).toDate(),
);
and with how I pass data in to it:
final ref = FirebaseDatabase.instance.ref();
final snapshot = await ref.child(...).get();
if (snapshot.exists) {
var m = Message.model(map: snapshot.value as Map))
} else {
print('No data available.');
}
The code in your question doesn't show how snapshot is initialized, but my guess is that it contains a list of messages. Even a list of 1 messages is still a list, so you have to handle that in your code by iterating of the children property of the snapshot:
snapshot.children.forEach((msgSnapshot) {
final data = Map<String, dynamic>.from(msgSnapshot.value as Map);
Message message = Message.fromJson(data);
print('message value${message.message}');
})
Your JSON should look like this:
{"userId": "4dca8440-a37d-11ec-9c66-9b8f61be17f0", "message": "777777"}

Flutter Firebase async query not retrieving data inside a stream function

I am trying to query a User from firebase within another query but for some reason but I can't get the code to work
The function the wont run is await usersRef.doc(uid).get(); and can be found here:
static getUserData(String uid) async {
return await usersRef.doc(uid).get();
}
static DirectMessageListModel getDocData(QueryDocumentSnapshot qdoc, String uid) {
Userdata postUser = Userdata.fromDoc(getUserData(uid));
return DirectMessageListModel.fromDoc(qdoc, postUser);
}
static DirectMessageListModel fromDoc(QueryDocumentSnapshot doc, Userdata altUser) {
return DirectMessageListModel(
doc['chatId'],
doc['lastMsgContent'],
doc['lastMsgType'],
altUser
);
}
parent function:
Stream<List<DirectMessageListModel>> getMeassageList(){
var snaps = FirebaseFirestore.instance.collection('directMessages').where('users', arrayContains: userdata!.uid).snapshots();
List<String> usersListElement = [];
return snaps.map((event) { return event.docs.map((e) {
usersListElement = [e.get('users')[0], e.get('users')[1]];
usersListElement.remove(userdata!.uid);
return DirectMessageListModel.getDocData(e, usersListElement.first);
}).toList();
});
}
You forgot to wait for the future getUserData(uid) to complete.
Try this:
static Future<DocumentSnapshot<Object>> getUserData(String uid) async {
return await usersRef.doc(uid).get();
}
static DirectMessageListModel getDocData(
QueryDocumentSnapshot qdoc,
String uid,
) async {
Userdata postUser = Userdata.fromDoc(await getUserData(uid)); // await here
return DirectMessageListModel.fromDoc(qdoc, postUser);
}
..
// parent function.
// Also wait for the future in the parent function.
// UPDATE BELOW! Define the parent function like this:
Stream<List<Future<DirectMessageListModel>>> getMeassageList() {
var snaps = FirebaseFirestore.instance
.collection('directMessages')
.where('users', arrayContains: userdata!.uid)
.snapshots();
List<String> usersListElement = [];
return snaps.map((event) {
return event.docs.map((e) async {
usersListElement = [e.get('users')[0], e.get('users')[1]];
usersListElement.remove(userdata!.uid);
return await DirectMessageListModel.getDocData(e, usersListElement.first);
}).toList();
});
}
NB: You are fetching user data (either sender/receiver) for each message in directMessages collection. It might be better to store just sender/receiver name in directMessages collection and simply display that. Then if the user clicks on a message, you can then fetch the full sender/receiver data.

Flutter - Creating Document Collection from an existing Document Collection Error : path.isNotEmpty

Please help me, i'm new to Firebase and i have a message error when i'm trying to create a collection from an existing collection ID.
The conversation is created and the ChatRoom also but i have the message appearing and disappearing after around 10 secondes, it seems as the second function doesn't wait the first one
Here's the structure :
Create a document in "Conversations" collection.
Getting the ID of that document.
Create a document in "ChatRoom" collection that has the same ID as
the document in "Conversations".
Here's the message error :
The following assertion was thrown building chatPage(dirty, state: _chatPageState#e5c15):
a document path must be a non-empty string
'package:cloud_firestore/src/collection_reference.dart':
Failed assertion: line 59 pos 14: 'path.isNotEmpty'
Here's my code :
class chatPage extends StatefulWidget {
#override
_chatPageState createState() => _chatPageState();
static String conversationId = "";
}
final CollectionReference conversationRef =
FirebaseFirestore.instance.collection("Conversations");
Future<String> getConversationID() async {
//Initialize Conversations collection
final QuerySnapshot snapshot = await conversationRef.get();
String convId = "";
snapshot.docs.forEach((DocumentSnapshot doc) {
if (doc["NumTel_Parent"] == OTPScreen.numTelParent &&
doc["Rendu"] == "Null") {
_isConv = true;
print("Conversation already Exist");
convId = doc.id;
}
});
if (_isConv == false) {
print("Adding conversation ...");
await bambiDB().addConversation(OTPScreen.numTelParent, "Null", "Null");
snapshot.docs.forEach((DocumentSnapshot doc1) {
if (doc1["NumTel_Parent"] == OTPScreen.numTelParent &&
doc1["Rendu"] == "Null") {
_isConv = true;
print("Conversation created");
convId = doc1.id;
}
});
}
return convId;
}
createChatRoomMessageAuto() async {
final CollectionReference chatRoomRef = FirebaseFirestore.instance
.collection("ChatRoom")
.doc(chatPage.conversationId)
.collection("ChatRoomParent");
final QuerySnapshot snapshot = await chatRoomRef.get();
if (snapshot.docs.length == 0) {
chatRoomRef.add({
"Message": messageAuto1,
"DateMessage": DateTime.now(),
"Who": "Doctor"
}).then((_) {
print("auto1 created");
}).catchError((_) {
print("an error occured");
});
chatRoomRef.add({
"Message": messageAuto2,
"DateMessage": DateTime.now(),
"Who": "Doctor"
}).then((_) {
print("auto2 created");
}).catchError((_) {
print("an error occured");
});
chatRoomRef.add({
"Message": messageAuto3,
"DateMessage": DateTime.now(),
"Who": "Doctor"
}).then((_) {
print("auto3 created");
}).catchError((_) {
print("an error occured");
});
chatRoomRef.add({
"Message": messageAuto4,
"DateMessage": DateTime.now(),
"Who": "Doctor"
}).then((_) {
print("auto4 created");
}).catchError((_) {
print("an error occured");
});
} else {
print("Auto already created.");
}
}
void creatingChatRoom() async {
chatPage.conversationId = "";
chatPage.conversationId = await getConversationID();
createChatRoomMessageAuto();
setState(() {});
}
#override
void initState() {
// TODO: implement initState
super.initState();
creatingChatRoom();
}
Welcome to SO! I'm having trouble understanding the code fully. It seems like some may be missing, specifically a complete definition of _chatPageState(). As a tip for future questions, you'll generally find it easier to get responses if you can strip the code back to a simplified example where possible.
My first line of thought is: does it work if conversationId is a value inside the _chatPageState instead of being a static property of chatPage?
My second thought is: does it work if you chain the two async functions like this?
getConversationID().then((id) {
chatPage.conversationId = id;
createChatRoomMessageAuto();
});
If the latter works, you probably may not even need to store conversationId at all as you might be able to pass it straight through to the createChatRoomMessageAuto function like
getConversationID().then((id) {
createChatRoomMessageAuto(id);
});
Me playing with a simplified version if it helps
Thank you for your help it works now, indeed i didn't put all the code sorry for not being too much clear.

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

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();
}
}

DateTime not a subtype of type TimeStamp/Unhandled Exception: Invalid argument: Instance of 'Future<LocationData>

So I am using the nearby connections API to discover devices around me and store their data in firestore however I keep getting 2 warnings about the location I am getting from the user that I came in contact with and the time i came in contact with them
These are the 2 warnings:
1)DateTime not a subtype of type TimeStamp
2)Unhandled Exception: Invalid argument: Instance of Future<.LocationData.>
as I try to add these values to firestore
here is my discovery method:
void discovery() async {
try {
bool a = await Nearby().startDiscovery(loggedInUser.email, strategy,
onEndpointFound: (id, name, serviceId) async {
print('I saw id:$id with name:$name'); // the name here is an email
var docRef =
_firestore.collection('users').document(loggedInUser.email);
// When I discover someone I will see their email
docRef.collection('met_with').document(name).setData({
'email': await getUsernameOfEmail(email: name),
'contact time': DateTime.now() as Timestamp ,
'contact location': location.getLocation(),
});
}, onEndpointLost: (id) {
print(id);
});
print('DISCOVERING: ${a.toString()}');
} catch (e) {
print(e);
}
}
This is another method where I retrieve the info I discovered from firestore:
void addContactsToList() async {
await getCurrentUser();
_firestore
.collection('users')
.document(loggedInUser.email)
.collection('met_with')
.snapshots()
.listen((snapshot) {
for (var doc in snapshot.documents) {
String currEmail = doc.data['email'];
DateTime currTime = doc.data.containsKey('contact time')
? (doc.data['contact time'] as Timestamp).toDate()
: null;
String currLocation = doc.data.containsKey('contact location')
? doc.data['contact location']
: null;
String _infection = doc.data['infected'];
if (!contactTraces.contains(currEmail)) {
contactTraces.add(currEmail);
contactTimes.add(currTime);
contactLocations.add(currLocation);
infection.add(_infection);
}
}
setState(() {});
print(loggedInUser.email);
});
}
Any fix for this please?
Use an async function to convert the Future<.LocationData.> to LocationData.
var data;
void convertData() async{
var futuredata = await FutureLocationData;
setState(() {
data = futuredata });
}

Resources