I asked a question before about Dart encoding/decoding to JSON, however, the libraries that were suggested were not complete and I decided to manually handle that.
The objective is to convert these objects to a map.
class Parent extends Object {
int id;
String name;
List<Child> listChild = new List<Child>();
Map toMap() => {"id":id, "name":name, "listChild":listChild};
}
class Child extends Object {
int id;
String childName;
Map toMap() => {"id":id, "childName":childName};
}
When doing
print(JSON.encode(parent.toMap()));
I am seeing it go here, any suggestion how to make this work?
if (!stringifyJsonValue(object)) {
checkCycle(object);
try {
var customJson = _toEncodable(object);
if (!stringifyJsonValue(customJson)) {
throw new JsonUnsupportedObjectError(object);
}
_removeSeen(object);
} catch (e) {
throw new JsonUnsupportedObjectError(object, cause : e);
}
}
}
Map toMap() => {"id":id, "name":name: "listChild": listChild.map((c) => c.toJson().toList())};
is valid for JSON.
import 'dart:convert' show JSON;
...
String json = JSON.encode(toMap());
You can also use the toEncodeable callback - see How to convert DateTime object to json
If your class structure does not contain's any inner class then follow
class Data{
String name;
String type;
Map<String, dynamic> toJson() => {
'name': name,
'type': type
};
}
If your class uses inner class structure
class QuestionTag {
String name;
List<SubTags> listSubTags;
Map<String, dynamic> toJson() => {
'name': name,
'listSubTags': listSubTags.map((tag) => tag.toJson()).toList()
};
}
class SubTags {
String tagName;
String tagDesc;
SubTags(this.tagName, this.tagDesc);
Map<String, dynamic> toJson() => {
'tagName': tagName,
'tagDesc': tagDesc,
};
}
Just rename Map toMap() into Map toJson() and it will work fine. =)
void encode() {
Parent p = new Parent();
Child c1 = new Child();
c1 ..id = 1 ..childName = "Alex";
Child c2 = new Child();
c2 ..id = 2 ..childName = "John";
Child c3 = new Child();
c3 ..id = 3 ..childName = "Jane";
p ..id = 1 ..name = "Lisa" ..listChild = [c1,c2,c3];
String json = JSON.encode(p);
print(json);
}
class Parent extends Object {
int id;
String name;
List<Child> listChild = new List<Child>();
Map toJson() => {"id":id, "name":name, "listChild":listChild};
}
class Child extends Object {
int id;
String childName;
Map toJson() => {"id":id, "childName":childName};
}
Related
Why the getCurrencyFromAPI function returns Intance of currency instead of the value itself. Is there some thing wrong with my model class?
This is the function
import 'dart:convert';
import 'package:app_bloc/data/models/currency.dart';
import 'package:http/http.dart' as http;
import 'package:app_bloc/constants/api_urls.dart';
class Repository {
Future<dynamic> getCurrencyFromAPI() async {
final res = await http.get(Uri.parse(coinbaseURL));
if (res.statusCode == 200) {
final resData = jsonDecode(res.body);
final data = resData['data'] as List;
List<Currency> list = [];
for (var e in data) {
final a = Currency.fromJson(e);
list.add(a);
}
print(list);
} else {
throw Exception('Error fetching data from API');
}
}
}
void main(List<String> args) {
Repository repo = Repository();
repo.getCurrencyFromAPI();
}
this is the model class
class Currency {
String id;
String name;
String minSize;
Currency({required this.id, required this.name, required this.minSize});
factory Currency.fromJson(Map<String, dynamic> data) {
final id = data['id'] as String;
final name = data['name'] as String;
final minSize = data['min_size'] as String;
return Currency(id: id, name: name, minSize: minSize);
}
}
Your Currency class does not have a toString method. That means it inherits the default from Object which returns Instance of 'Currency'.
When you print the List<Currency> it calls toString on every element to get a string representation. So, that's what you see. It is a Currency object.
Try adding:
String toString() => "Currency(id: $id, name: $name, minSize: $minSize)";
to you Currency class and see if it makes a difference.
Currency currencyModelFromJson(String str) => Currency.fromJson(json.decode(str));
class Currency {
String id;
String name;
String minSize;
Currency({required this.id, required this.name, required this.minSize});
factory Currency.fromJson(Map<String, dynamic> data) {
final id = data['id'] as String;
final name = data['name'] as String;
final minSize = data['min_size'] as String;
return Currency(id: id, name: name, minSize: minSize);
}
}
Then do this :
class Repository {
Future<dynamic> getCurrencyFromAPI() async {
final res = await http.get(Uri.parse(coinbaseURL));
if (res.statusCode == 200) {
final resData = jsonDecode(res.body);
final data = resData['data'] as List;
List<Currency> list = [];
for (var e in data) {
final a = currencyModelFromJson(e); // change here
list.add(a);
}
print(list);
} else {
throw Exception('Error fetching data from API');
}
}
}
I'm new to Dart 2. I want a class to have a property. It's a reference of other class. it's not an instance but class itself. In TypeScript, it's possible to write as below. Is there a same way in Dart 2?
class Item { }
class ItemList {
itemClass: typeof Item;
}
const itemList = new ItemList();
itemList.itemClass = Item;
UPDATED:
I added some more context. The following is minimal sample code. I want to delegate a role of instantiation to super class.
class RecordBase {
id = Math.random();
toJson() {
return { "id": this.id };
};
}
class DbBase {
recordClass: typeof RecordBase;
create() {
const record = new this.recordClass();
const json = record.toJson();
console.log(json);
}
}
class CategoryRecord extends RecordBase {
toJson() {
return { "category": "xxxx", ...super.toJson() };
};
}
class TagRecord extends RecordBase {
toJson() {
return { "tag": "yyyy", ...super.toJson() };
};
}
class CategoryDb extends DbBase {
recordClass = CategoryRecord;
}
class TagDb extends DbBase {
recordClass = TagRecord;
}
const categoryDb = new CategoryDb();
categoryDb.create();
const tagDb = new TagDb();
tagDb.create();
I have tried to make you sample code into Dart. As I told before, you cannot get a reference to a class and call the constructor on runtime based on this reference.
But you can make a reference to a method which constructs the object of you class.
import 'dart:math';
class RecordBase {
static final Random _rnd = Random();
final int id = _rnd.nextInt(100000);
Map<String, dynamic> toJson() => <String, dynamic>{'id': id};
}
abstract class DbBase {
final RecordBase Function() getRecordClass;
RecordBase record;
Map<String, dynamic> json;
DbBase(this.getRecordClass);
void create() {
record = getRecordClass();
json = record.toJson();
print(json);
}
}
class CategoryRecord extends RecordBase {
#override
Map<String, dynamic> toJson() {
return <String, dynamic>{'category': 'xxxx', ...super.toJson()};
}
}
class TagRecord extends RecordBase {
#override
Map<String, dynamic> toJson() {
return <String, dynamic>{'tag': 'yyyy', ...super.toJson()};
}
}
class CategoryDb extends DbBase {
CategoryDb() : super(() => CategoryRecord());
}
class TagDb extends DbBase {
TagDb() : super(() => TagRecord());
}
void main() {
final categoryDb = CategoryDb();
categoryDb.create(); // {category: xxxx, id: 42369}
final tagDb = TagDb();
tagDb.create(); // {tag: yyyy, id: 97809}
}
I am not really sure if the create() method should be seen as a method or a constructor. So I choose to make it a method to be closer to your code.
How to get one by one values in Nested structures with Lists json structure.
controller.dart
final jsonResponse = json.decode(response.body);
AssetRegister model = AssetRegister.fromJson(jsonResponse);
print(model.data);
how to print like this print(model.dart.i);//error
model.dart
class AssetRegister {
final List<Data> data;
AssetRegister({this.data});
factory AssetRegister.fromJson(Map<String, dynamic> json) {
var list = json['data'] as List;
print(list.runtimeType);
List<Data> assetList = list.map((i) => Data.fromJson(i)).toList();
return AssetRegister(data: assetList);
}
}
class Data {
final int i;
final String d;
Data({this.i, this.d});
factory Data.fromJson(Map<String, dynamic> json) {
return Data(
i: json['i'],
d: json['d'],
);
}
}
You should provide toString method implementation for Data class like this:
class Data {
final int i;
final String d;
Data({this.i, this.d});
factory Data.fromJson(Map<String, dynamic> json) {
return Data(
i: json['i'],
d: json['d'],
);
}
#override
String toString() => return 'i = $i, $d';
}
Calling API but showing error, I'm unable to parse data in the bean class.
My Response:
{
"error":"0",
"status":200,
"deliveryCharge":"14.00",
"image_base_url":"http:\/\/xxxxx.tk\/assets\/event\/image\/",
"image_logo_url":"http:\/\/xxxxx.tk\/assets\/event\/logo\/",
"eventList":[
{
"event_id":"1",
"event_name":"Syscraft Premier League",
"event_location":"12 ny valleys",
"event_type_id":"15",
"start_date":"2019-01-10 03:21:00",
"end_date":"2019-01-26 16:10:00",
"event_logo":"f4f0bfc168a3816891e2749232c5243f.jpg"
},
{
"event_id":"3",
"event_name":"Republic Day Event 2019",
"event_location":"AH-654 Villa No. 42 New Township New Township",
"event_type_id":"1",
"start_date":"2019-01-26 00:00:00",
"end_date":"2019-01-26 11:55:00",
"event_logo":"3a4a7fabbbd7ed8febf67bacda71ae48.jpg"
}
]
}
Calling Api
Future<List<EventResponse>> fetchEvent( ) async {
String url='http://xxxxxxxxxxxxxxx.tk/api/userapp/event/lists';
var headers = new Map();
headers['Auth-Key'] = 'OCDOC#2018';
headers['End-Client'] = 'OCDOC';
var body = new Map();
headers['schedule'] = 'present';
http.Response res = await http.post(url,headers: headers, body: body);
final Map<String,dynamic> parsed=json.decode(res.body); // post api call
print("Reposnce Event:---"+parsed.toString());}
My Bean class
class EventResponse{
String error;
int status;
String deliveryCharges;
String imageBaseUrl;
String imageLogoUrl;
List<Event> eventList;
EventResponse({
this.error,
this.status,
this.deliveryCharges,
this.imageBaseUrl,
this.imageLogoUrl,
this.eventList
});
factory EventResponse.convertEventResponse(Map<String,dynamic> json){
return EventResponse(
error: json['error'],
status: json['status'],
deliveryCharges: json['deliveryCharge'],
imageBaseUrl: json['image_base_url'],
imageLogoUrl: json['image_logo_url'],
eventList: json['eventList']);
}}
class Event{
String eventId;
String eventName;
String location;
String event_logo;
Event({
this.eventId,
this.eventName,
this.location,
this.event_logo,
});
factory Event.convertEvent(Map<String,dynamic> json){
return Event(
eventId: json['event_id'],
eventName: json['event_name'],
location: json['event_location'],
event_logo: json['event_logo'],
);}}
Showing Error
_InternalLinkedHashMap<dynamic, dynamic> is not a subtype of type Map<String, String>
Rewrite EventResponse like this:
class EventResponse {
String error;
int status;
String deliveryCharges;
String imageBaseUrl;
String imageLogoUrl;
List<Event> eventList;
EventResponse(
{this.error,
this.status,
this.deliveryCharges,
this.imageBaseUrl,
this.imageLogoUrl,
this.eventList});
factory EventResponse.convertEventResponse(Map<String, dynamic> json) {
List<dynamic> events = json['eventList'];
List<Event> eventList = events.map((e) => Event.convertEvent(e)).toList();
return EventResponse(
error: json['error'],
status: json['status'],
deliveryCharges: json['deliveryCharge'],
imageBaseUrl: json['image_base_url'],
imageLogoUrl: json['image_logo_url'],
eventList: eventList,
);
}
}
I have changed EventResponse as #Richard Heap did.
factory EventResponse.convertEventResponse(Map<String, dynamic> json) {
List<dynamic> events = json['eventList'];
List<Event> eventList = events.map((e) => Event.convertEvent(e)).toList();
return EventResponse(
error: json['error'],
status: json['status'],
deliveryCharges: json['deliveryCharge'],
imageBaseUrl: json['image_base_url'],
imageLogoUrl: json['image_logo_url'],
eventList: eventList,
);
}
}
One more thing I need to change is when I post parameters and headers need to define their Map() to Map<String,String>().
Future<EventResponse> fetchEvent( ) async { // here i change Future type
String url='http://xxxxxxx-oceanapparel.tk/api/userapp/event/lists';
var headers = new Map<String, String>(); //here i defined Map type
headers['Auth-Key'] = 'OCDOC#2018';
headers['End-Client'] = 'OCDOC';
var body = new Map<String, String>(); //here i defined Map type
headers['schedule'] = 'present';
http.Response res = await http.post(url,headers: headers, body: body);
print("Reposnce Event:---"+res.body);
}
i try to build a map to add it into firestore.
Produkt Class:
class Produkt{
String name;
int anzahl;
Produkt({
this.name,
this.anzahl,
});
factory Produkt.fromJson(Map<String, dynamic> parsedJson){
return Produkt(
name:parsedJson['Name'],
anzahl:parsedJson['Anzahl']
);
}
Map<String, dynamic> toProduktJson() =>
{
"Name" : name,
"Anzahl" : anzahl
};
}
ProduktList Class:
class ProduktList{
final List<Produkt> produkte;
ProduktList({
this.produkte,
});
factory ProduktList.fromJson(Map<String, dynamic> parsedJson){
var list = parsedJson["Produkte"] as List;
List<Produkt> produkte = list.map((i) => Produkt.fromJson(i.cast<String, dynamic>())).toList();
return ProduktList(
produkte: produkte,
);
}
Map<String, dynamic> toProdukteJson() =>
{
"Produkte" : [
produkte[0].toProduktJson(),
produkte[1].toProduktJson(),
produkte[2].toProduktJson(),
]
};
}
I wanted that the Map looks like:
{
"Produkte" : [
produkte[0].toProduktJson(),
produkte[1].toProduktJson(),
produkte[2].toProduktJson(),
]
};
But if the List produkte has a length of 2, the Map should have 2 and it the List have a length of 10, the Map should have 10 entries.
How can i do this?
Pls help me.
Thank you
An option would be the following:
Map<String, dynamic> toProdukteJson() {
Map map = new Map<String, dynamic>();
if (produkte != null) {
map["produkte"] = produkte.map((produkt) => produkt.toJson()).toList();
}
return map;
}
class Produkt {
final String id;
...
Produkt(this.id, ...);
Map toJson() => {'id' : id, ...};
}