I am returning multiple records as JSON and need to fill an object with them. How is done in Dart?
HomeCategory(0, Icons.check, Colors.blue[800], "Check In", [Task(0, "Check In", true),]),
The JSON result has all this data.
Deserialize the JSON string into a map:
import 'dart:convert';
...
Map<String, dynamic> jsonObj = json.decode(jsonString);
Then create a factory constructor for your class that converts the map into your object:
class HomeCategory {
final int id;
final String iconCode;
final String colorCode;
final String message;
final List<Task> tasks;
HomeCategory(
this.id,
this.iconCode,
this.colorCode,
this.message,
this.tasks,
);
HomeCategory.fromJson(Map<String, dynamic> jsonObj) {
int id = jsonObj['id'];
String iconCode = jsonObj['iconCode'];
String colorCode = jsonObj['colorCode'];
String message = jsonObj['message'];
List<Task> tasks = [];
var tasksObj = jsonObj['tasks'];
if (tasksObj != null && tasksObj is List) {
tasks = tasksObj.map((taskObj) => Task.fromJson(taskObj)).toList();
}
return HomeCategory(id, iconCode, colorCode, message, tasks);
}
Tailor the above code to the structure of your HomeCategory and Task classes as well as the structure of your JSON. (You're going to need to give the Task class a fromJson constructor as well, of course.)
EDIT: If your incoming JSON object is a list, you can simply change how you use the deserialized json object:
List<dynamic> jsonList = json.decode(jsonString);
List<HomeCategory> homeCategories = jsonList.map((jsonObj) => HomeCategory.fromJson(jsonObj)).toList();
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 currently working on an app where the user is able to store data on their device locally. Therefor I am using the sqflite package but I am running into some errors converting my Class data into Json.
This is the error message I get:
A value of type 'Set' can't be returned from the method
'toJson' because it has a return type of 'Map<String, Widget>'.
due to this line:
Map<String, Widget> toJson() => {
EntryFields.id = id,
EntryFields.name = name,
EntryFields.navigation = navigation,
};
This is my class:
import 'package:flutter/material.dart';
const String tableFavs = 'favorites';
class EntryFields {
static late String id = '_id';
static late String name = '_name';
static late String navigation = '_navigation';
}
class Entries {
final int id;
final String name;
final Widget navigation;
Entries({
required this.id,
required this.name,
required this.navigation,
});
Map<String, Widget> toJson() => {
EntryFields.id = id,
EntryFields.name = name,
EntryFields.navigation = navigation,
};
}
and this is a snipped from my database:
Future<Entries> create(Entries entries) async {
final db = await instance.database;
final id = await db.insert(tableFavs, entries.toJson());
}
you can't store a widget in the database it should be Map<String, String>
try to store the parameters of the widget as a String, not the whole widget
you can store these types double, string, int, bool..
try using the below code
class EntryFields {
static late String id = '_id';
static late String name = '_name';
static late String navigation = '_navigation';
}
class Entries {
const Entries({
this.id,
this.name,
this.navigation,
});
final String? id;
final String? name;
final String? navigation;
Map<String, dynamic> toJson() => {
"_id": id,
"_name": name,
"_navigation": navigation,
};
}
Future<void> create(Entries entries) async {
final db = await instance.database;
final id = await db.insert(tableFavs, entries.toJson());
}
void main(){
final entriesFromField = Entries(
id: EntryFields.id,
name: EntryFields.name,
navigation: EntryFields.navigation
);
create(entriesFromField);
}
or better you can use this json generator
I use complex objects to manage data in my app. For example I have an object defined by the "Defi class" (meaning Challenge in French).
Here is the Defi class :
class Defi {
final int modeApprentissage;
final DateTime date;
final double score;
final int seconds;
final List mots;
final List erreurs;
final List listes;
final int langue;
final int type;
final int typeMots1;
final int typeMots2;
const Defi(
{required this.modeApprentissage,
required this.date,
required this.type,
required this.langue,
required this.typeMots1,
required this.typeMots2,
required this.score,
required this.seconds,
required this.listes,
required this.mots,
required this.erreurs});
}
I have a LIST of Defi that I would like to save on FIREBASE FIRESTORE.
My question : Is it absolutely necessary to transform my list of Defi into a map to save it on Firestore ? Or is there another way ?
Here is how I do it :
List _defisMap = [];
for (Defi def in _defis) {
_defisMap.add({
'modeApprentissage': def.modeApprentissage,
'type': def.type,
'langue': def.langue,
'typeMots1': def.typeMots1,
'typeMots2': def.typeMots2,
'date': def.date,
'score': def.score,
'seconds': def.seconds,
'listes': def.listes,
'mots': def.mots,
'erreurs': def.erreurs,
});
}
if (await _connectivity.checkConnectivity() != ConnectivityResult.none) {
await FirebaseFirestore.instance
.collection('familyAccounts')
.doc(_accountEmail)
.update({
'defis': _defisMap,
});
I read in some article that in classes such as Defi, I could add a "factory" constructor ? Does this have anything to do with what I'd like to do ?
I created another class :
class Classes {
final String code;
final String nom;
const Classes({
required this.code,
required this.nom,
});
Map<String, dynamic> toJson() => {
'code': code,
'nom': nom,
};
factory Classes.fromMap(Map data) => Classes(
code: data['code'] ?? '',
nom: data['nom'] ?? '',
);
}
I save a list of Classes on Firestore. No problem.
But to retrieve this list : I must go from the list of maps that is on Firestore to a list of "Classes". And I just can't get the syntax right !
Here is my code :
final DocumentSnapshot<Map<String, dynamic>> docInfo =
await FirebaseFirestore.instance
.collection('familyAccounts')
.doc(_accountEmail)
.get();
_typeCompte =
docInfo['typeCompte'] == 'prof' ? TypeCompte.prof : TypeCompte.eleve;
_userId = docInfo['userId'];
_linked = docInfo['linked'];
_name = docInfo['name'];
_avatar = docInfo['avatar'];
_classe = docInfo['classe'];
_classeCode = docInfo['classeCode'];
_country = docInfo['country'];
_region = docInfo['region'];
docInfo['langue'] == 'french'
? _selectedIoLanguage = Language.french
: _selectedIoLanguage = Language.english;
_teacherCode = docInfo['teacherCode'];
_indexList = docInfo['indexList'];
_nbrList = docInfo['nbrList'];
_dateCreationCompte = docInfo['dateCreation'].toDate();
_defiTemp = docInfo['defis'].toList();
if (_typeCompte == TypeCompte.prof) {
_etablissement = docInfo['etablissement'];
_mesClasses = docInfo['mesClasses'];
(_mesClasses should be a list of "Classes").
I sense it should be some kind of xxx.map() etc.... but I don't master this syntax.
You need to create toJson method to set as a map of your list. If you have a list of Defi class. You can send it to map.
class Defi {
final int modeApprentissage;
final DateTime date;
final double score;
final int seconds;
final List mots;
final List erreurs;
final List listes;
final int langue;
final int type;
final int typeMots1;
final int typeMots2;
const Defi(
{required this.modeApprentissage,
required this.date,
required this.type,
required this.langue,
required this.typeMots1,
required this.typeMots2,
required this.score,
required this.seconds,
required this.listes,
required this.mots,
required this.erreurs});
Map<String, dynamic> toJson() => {
'modeApprentissage': modeApprentissage,
'type': type,
'langue': langue,
'typeMots1': typeMots1,
'typeMots2': typeMots2,
'date': date,
'score': score,
'seconds': seconds,
'listes': listes,
'mots': mots,
'erreurs': erreurs,
};
}
Your list name is should be List<Defi> _defis then map it with toJson. var jsonMap = _defisMap.map((e) => e.toJson()).toList();
var jsonMap = _defis.map((e) => e.toJson()).toList();
if (await _connectivity.checkConnectivity() != ConnectivityResult.none) {
await FirebaseFirestore.instance
.collection('familyAccounts')
.doc(_accountEmail)
.update({
'defis': jsonMap,
});
You can also Map it from api call with fromJson method. Here is the way. Add this to your Defi class.
factory Defi.fromJson(Map<String, dynamic> json) {
return Defi(
modeApprentissage: json['modeApprentissage'],
type: json['type'],
langue: json['langue'],
typeMots1: json['typeMots1'],
typeMots2: json['typeMots2'],
date: json['date'],
score: json['score'],
seconds: json['seconds'],
listes: json['listes'],
mots: json['mots'],
erreurs: json['erreurs'],);
}
And when you call api you need to call that function.
final Map<String, dynamic> jsonResult = json.decode(response.body);
//if it is a list returning from api. You can change variables what you got from api.
(jsonResult as List<dynamic>)
.map((data) => Defi.fromJson(data))
.toList();
// if it is not list
Defi.fromJson(jsonResult);
Yes, it's absolutely necessary to transform into a map. Firestore is a document store, the definition of a document is a json object, which is represented by a map in Dart. BUT, you don't have to do it "manually". Most of us use packages to do the mapping for us.
Freezed or JsonSerializable and then we simply call .toJson and pass that to the function. In addition to that Firestore now supports the .withConverter function so you don't have to do any conversion if you know what type the collection is storing.
So if you know the type of a collection is Defi you can do
final defyCollection = FirebaseFirestore.instance.collection('defis').withConverter<Defi>(
fromFirestore: (snapshot, _) {
final data = snapshot.data()!;
data['id'] = snapshot.id;
return Defi.fromJson(data);
},
toFirestore: (object, _) => object.toJson(),
)
This way you can simply use the defyCollection and the data property or function will be typed to your type.
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 want to convert a list of 'Box' objects to a json file and also read it back in (json file to a list a 'Box' objects), but I'm a bit stuck on the implementation. I have written the below code, but I can only write a single 'Box' object to the json and convert a single 'Box' object back. When I try to do this with a list I hit errors like data that gets overwritten or just a single object that gets returned.
So in short, I want to write a List to json and convert json to List
I have the following data structure
Box model
class Box {
final String nameBox;
final List<Item> items;
Box({#required this.nameBox, #required this.items});
factory Box.fromJson(Map<String, dynamic> json) {
var items = json['items'];
List<Item> itemsList = items.cast<Item>();
return new Box(
nameBox: json["nameBox"],
items: itemsList
);
}
Map<String, dynamic> toJson() => {
"nameBox": nameBox,
"items": items,
};
}
Box fromJson(String boxData) {
return Box.fromJson(json.decode(boxData));
}
String toJson(Box box) {
return json.encode(box.toJson());
}
Item model
class Item {
final String itemName;
final int quantity;
Item({#required this.itemName, #required this.quantity});
factory Item.fromJson(Map<String, dynamic> json) {
return new Item(itemName: json["itemName"], quantity: json["quantity"]);
}
Map<String, dynamic> toJson() => {
"itemName": itemName,
"quantity": quantity,
};
}
Item fromJson(String itemData) {
return Item.fromJson(json.decode(itemData));
}
String toJson(Item item) {
return json.encode(item.toJson());
}
writeToJson function
Future writeJson(Box box) async {
final file = await _localFile;
List<Box> tempRead = await returnBoxes();
if (tempRead.isEmpty || tempRead == null) {
return;
}
tempRead.add(box);
file.writeAsString(json.encode(tempRead));
}
readJson function
Future<List<Box>> returnBoxes() async {
final file = await _localFile;
List<Box> boxList = new List<Box>();
Map<String, dynamic> content = await json.decode(file.readAsStringSync());
boxList.add(Box.fromJson(content));
return boxList;
}
I also tried to cast the json content to a list, but then I hit some iterable errors. Any who can help me out?
JSON has this idiosyncrasy that everything is either an object or an array, and you don't know what you get until you decode it. Dart decodes the two json types into a Map<String, dynamic> and List<dynamic> respectively. (The reason that you get dynamic is because each of them could itself then be a value, a json array or a json object, recursively.)
Dart encodes a Dart object by calling toJson on it and a Dart list by emitting a [ then each member of the list then a ].
Knowing that, it's easy to encode and decode arrays/lists. (I removed all the unnecessary code.)
class Box {
final String nameBox;
final List<Item> items;
Box({#required this.nameBox, #required this.items});
factory Box.fromJson(Map<String, dynamic> json) => Box(
nameBox: json['nameBox'],
items: json['items'].map<Item>((e) => Item.fromJson(e)).toList(),
);
Map<String, dynamic> toJson() => {
'nameBox': nameBox,
'items': items,
};
}
class Item {
final String itemName;
final int quantity;
Item({#required this.itemName, #required this.quantity});
factory Item.fromJson(Map<String, dynamic> json) => Item(
itemName: json['itemName'],
quantity: json['quantity'],
);
Map<String, dynamic> toJson() => {
'itemName': itemName,
'quantity': quantity,
};
}
Future writeJson(Box box) async {
final file = await _localFile;
var boxes = await returnBoxes();
/* I think you probably don't want this...
if (boxes.isEmpty || boxes == null) {
return;
}*/
// but rather, this
if (boxes == null) boxes = [];
boxes.add(box);
await file.writeAsString(json.encode(boxes));
}
Future<List<Box>> returnBoxes() async {
final file = await _localFile;
// because the json is an array (i.e. enclosed in []) it will be decoded
// as a Dart List<dynamic>
List<dynamic> d = json.decode(await file.readAsString());
// here we map the List<dynamic> to a series of Box elements
// each dynamic is passed to the Box.fromJson constructor
// and the series is formed into a List by toList
return d.map<Box>((e) => Box.fromJson(e)).toList();
}