I'm struggling a bit with getting data I push to Firebase Realtime DB in Flutter.
I'm using this code to push data to FB:
DatabaseReference newPostRef = news_dbRef.push();
final newKey = news_dbRef.child('News').push().key;
newPostRef.set({
"timestamp": timestamp,
"content": content_u,
"title": title_u,
"imgURL": imageUrl_u.substring(0,imageUrl_u.lastIndexOf('?')),
"fileURL": fileUrl_u.substring(0,fileUrl_u.lastIndexOf('?')),
"user": _user
});
so it creates a desired object in Firebase like this:
screenshot from Firebase
Now when I'm trying to get this data to my app, I'm having issues with proper serialization with it.
This is what I'm doing:
DatabaseReference newsCountRef =
FirebaseDatabase.instance.ref().child('News');
newsCountRef.onValue.listen((DatabaseEvent event) {
var data = event.snapshot.value;
String encoded = jsonEncode(data);
Map<String, dynamic> postslist = jsonDecode(encoded);
var somelist = postslist.entries.map((e) => TestNewsModel(e.key, e.value)).toList();
so it brings me to a stage that I have a list... but cannot read values for each line.
Do you have any ideas what I'm missing? Here's a class I'm using for serialization:
class TestNewsModel {
String recordid;
dynamic fields;
TestNewsModel(this.recordid, this.fields);
String toString() {
return '{ ${this.recordid}, ${this.fields} }';
}
}
class Field {
String timestamp;
String content;
String title;
String imgURL;
String fileURL;
String user;
Field({
required this.timestamp,
required this.content,
required this.title,
required this.imgURL,
required this.fileURL,
required this.user,
});
String toString() {
return '{ ${this.timestamp}, ${this.content}, ${this.title}, ${this.imgURL}, ${this.fileURL}, ${this.user} }';
}}
Would recommend creating a .fromDoc method in your class, similar to how you would create a .fromJson method.
Heres an example from one of my projects, this way you can avoid encoding and decoding.
///Creates a [Patient] from the information from a single firestore doc.
factory Patient.fromDoc(doc) {
return Patient(
doc.data()['email'],
doc.data()['forename'],
doc.data()['surname'],
doc.data()['hospitalNum'].toString(),
doc.id,
);
}
Related
This is my JSON:
{
'malls' : [{'id':1 , 'name': 'salam'},{'id':2 , 'name': 'salam2'}]
}
And this is my modeling JSON classes:
class MALL {
final int id;
final String name;
MALL({required this.id, required this.name});
factory MALL.fromJson(Map<String, dynamic> data) {
return MALL(id: data['id'], name: data['name']);
}
}
class City {
final List<MALL> malls;
City({required this.malls});
factory City.fromJson(Map<String, dynamic> data) {
var list = data['malls'] as List;
List<MALL> mallList = list.map((i) => MALL.fromJson(i)).toList();
return City(malls: mallList);
}
}
This is my get method:
Future<List<MALL>> get() async {
var response = await http.get(Uri.parse(URL), headers: {"authorization": "Bearer ${token}", "Content-Type": "application/json"});
var data = jsonDecode(response.body);
City api = City.fromJson(data);
return data['malls'];
}
I get this output:
[Instance of 'MALL', Instance of 'MALL']
I want my JSON in output by I got the instance of my classes.
How can I convert the instances to my data? It means I want to return my JSON in output and I can access the keys of malls in my FutureBuilder.
If you wanna print the response of a Class you can override the toString method to print the response of the Class. Example:
class MALL {
final int id;
final String name;
MALL({required this.id, required this.name});
factory MALL.fromJson(Map<String, dynamic> data) {
return MALL(id: data['id'], name: data['name']);
}
#override
String toString() => "{ id : $id, name : $name}";
}
Now you will see the result in console.
Inside your FutureBuilder yo will get list of Malls. Thats you have to use loop or list view builder to access those elemet.
if you want to print the list data. you have to print first element
inside your future build when data is loded.
print(data.first.toString())
add this line of code inside your malls calss
#override
String toString() => "{ id : $id, name : $name}";
I am new to dart and I am trying to create a basic inventory app with different types of chemicals.
I am trying to fetch data from firebase, which is getting back to me perfectly, but when I am trying to store it locally with a custom Model Class, its throwing me the following error
type 'int' is not a subtype of type 'String'
Here is the code for fetching and storing data locally
Future<void> getLoadedData() async {
final url = Uri.parse(
'https://inventory-db0eb-default-rtdb.asia-southeast1.firebasedatabase.app/chemicalList.json?auth=$authToken');
try {
final response = await http.get(url);
final List<ChemModel> _tempChemical = [];
final _tempChemList = json.decode(response.body) as Map<String, dynamic>;
_tempChemList.forEach((elementId, value) {
_tempChemical.add(
ChemModel(
id: ' ',
name: ' ',
// name: value['name'] ?? "Empty",
formula: ' ',
// formula: value['formula'] ?? "Empty",
description: ' ',
molWeight: double.parse(value['molWeight']),
// description: value['description'] ?? "Empty",)
),
);
});
_chemicalList = _tempChemical;
notifyListeners();
} catch (error) {
print(error);
rethrow;
}}
This is my model class
class ChemModel with ChangeNotifier {
String id;
String name;
String formula;
double molWeight;
String description;
ChemModel(
{required this.id,
required this.name,
required this.formula,
this.description = "",
this.molWeight = 0});
}
I'm not sure where I am going wrong.
You can convert a value to double as follows
molWeight: value['molWeight'].toDouble(),
or
molWeight: (value['molWeight'] as int).toDouble(),
model class may be a nuisance if you share a screenshot of the data source I can help more clearly
for exp : I mean, the value from the data source is string, and if you're trying to keep it as a int in the model class, you might get this kind of error.
I'm trying to create a function to return the articles list from the Firebase Realtime Database.
But it's not working.
I'm new to flutter.
My Database structure is like the following:
Below is the code I have written for that:
Future<List<ArticleModel>> getArticles() async {
List<ArticleModel> articles = [];
uid = FirebaseAuth.instance.currentUser!.uid;
var ref = FirebaseDatabase.instance.ref().child("saved").child(uid);
await ref.once().then((DatabaseEvent databaseEvent) {
var docs = databaseEvent.snapshot.children;
for (var element in docs) {
Map<dynamic, dynamic> data = jsonDecode(jsonEncode(element.value));
var article = ArticleModel.fromJson(Map<dynamic, dynamic>.from(data));
articles.add(article);
}
});
print(articles);//Its printing [Instance of 'ArticleModel', Instance of 'ArticleModel'.......
return articles;
}
Code for ArticleModel
class ArticleModel {
String sourceName;
String author;
String title;
String description;
String url;
String urlToImage;
String publishedAt;
ArticleModel(
{required this.sourceName,
required this.author,
required this.title,
required this.description,
required this.urlToImage,
required this.url,
required this.publishedAt});
factory ArticleModel.fromJson(Map<dynamic, dynamic> element) {
return ArticleModel(
author: element['author'],
description: element['desc'],
sourceName: element['source'],
publishedAt: element['time'],
title: element['title'],
url: element['url'],
urlToImage: element['urlImage'],
}
}
The problem is that you ArticleModel has a different fields name in the method .fromJson() from the data structure in the database, which is the dec key, you have written it in the model as desc.
So change:
description: element['desc'],
in ArticleModel to be:
description: element['dec'],
I receive an object from my payload data (which has to be a String) like this: {id: 24VQUCeGD4KnW6tvfhj8MJjuASk, event: user}. Since it is a string now, how can I access the key and value pair of both items in flutter from a String? I have tried creating a model class for it, making a Map again out of the String, decoding it back to json object but all failed. How can I get the key/value pair in a proper way?
Code:
await _notificationsPlugin.show(
id,
'New notification',
'You have received a new notification!',
notificationDetails,
payload: message.data.toString(), // the payload data has to be a string
);
When you press on the notification:
onSelectNotification: (String data) async {
//here is where I want to access the key/value pair of that String 'data'
// i tried something like this but failed
var someData = jsonEncode(jsonDecode(data));
var className = ClassName.fromJson(someData);
print(className.id);
.. but nothing prints
//... some logic
}
class ClassName {
ClassName({
this.id,
this.event,
});
String id;
String event;
ClassName.fromJson(Map<String, dynamic> json) {
id = json['id'];
user = json['event'];
}
}
Any form of help is appreciated!
try this:
import 'dart:convert';
void processData(String data) {
Map<String, dynamic> someData = jsonDecode(data);
var className = ClassName.fromJson(someData);
print(className.id);
}
class ClassName {
ClassName({
required this.id,
required this.user,
});
String id;
String user;
ClassName.fromJson(Map<String, dynamic> json) :
id = json['id'],
user = json['user'];
}
void main() {
processData("{\"id\": \"24VQUCeGD4KnW6tvfhj8MJjuASk\", \"user\": \"user\"}");
}
p.s it seems that your provided JSON has id and event keys but in your ClassName, you are reading id and user keys which doesn't exist.
it happens that the id string isn't delimited so, you may try to custom decode like:
Map<String, String> decodePayload(String eventData) {
final aString = eventData.substring(5, eventData.length - 1);
final parts = aString.split(', ');
final id = parts[0];
final event = parts[1].substring(7, );
return {'id': id, 'event':event};
}
It doesn't looks nice but it may works
I have two different endpoints.
"/api/users?page=1" with the response below :
{"users": [{"id":1, "name": "David"}, {"id": 2, "name": "Richard"}]}
"/api/pictures?page=2" with this response :
{"pictures": [{"userID": 1, "urls": ["https://b.co/c.png", "https://a.com/b.png"]}]}
What is the best solution to merge this two endpoints in OOP.
class User {
final int id;
final String name;
User(this.id, this.name);
}
class Picture {
final User user;
final List<String> pictures;
Picture(this.user, this.pictures);
factory Picture.fromJson(Map<String, dynamic> json) {
return Picture(
// Here I have to find json['userID'] from previously fetched users. I can use singletons but its an anti-pattern and not preferred.
, json['urls']
);
}
}
I'm not gonna change my server responses. please help me out.
I would await for both API returns and then have it be passed inside Picture class. Also, I would implement fromJson on User class too
class User {
final int id;
final String name;
User(this.id, this.name);
User.fromJson(Map<String, dynamic>) {
// .....
}
}
class Picture {
final User user;
final List<String> pictures;
Picture(this.user, this.pictures);
factory Picture.fromJson({
Map<String, dynamic> pictureJson,
Map<String, dynamic> userJson
}) {
final user = User.fromJson(userJson);
return Picture(
user: user;
// Here I have to find json['userID'] from previously fetched users. I can use singletons but its an anti-pattern and not preferred.
, json['urls']
);
}
}