I'm trying to convert some objects to json to send it to DB, this is the code I have now:
Map<String, dynamic> bag = {};
bag = {
'colors' : [
for(int i = 0; i < product.colors.length; i ++){
'id': product.colors[i].id,
'desc': product.colors[i].desc,
'sizes': [
for(int j=0; j < product.colors[i].sizes.length; j ++){
product.colors[i].sizes[j].toJson()
}
]
}]
};
print(json.encode(bag));
but the result I get is this:
Converting object to an encodable object failed: Instance of '_CompactLinkedHashSet<Map<String, dynamic>>'
How can I solve it?
Product class:
final String id;
final String desc;
final List<Colors> colors;
Colors:
final String id;
final String desc;
final List<Prices> prices;
Prices:
final String id;
final String desc;
final List<Types> types;
Types:
final String id;
final String desc;
final List<Sizes> sizes;
Sizes:
final String id;
final int stock;
final String desc;
final bool filled;
int quantity;
final double price;
I want the json like this:
colors:
id : 12
desc : black
sizes: [
id : 0202202
stock : 10
desc: Full Size
filled: true
quantity : 2
price : 200
]
The way you are creating the JSON is way too complicated. Try instead add a toJson() method on each of your classes. This method is automatically called by the Dart JSON encoder if it hits an object that is not compatible with JSON.
Here is an example:
import 'dart:convert';
class Product {
final String id;
final String desc;
final List<Colors> colors;
Product({
required this.id,
required this.desc,
required this.colors,
});
Map<String, Object> toJson() => {
'id': id,
'desc': desc,
'colors': colors,
};
}
class Colors {
final int id;
final String desc;
final List<Prices> prices;
Colors({
required this.id,
required this.desc,
required this.prices,
});
Map<String, Object> toJson() => {
'id': id,
'desc': desc,
'prices': prices,
};
}
class Prices {
final String id;
final String desc;
final List<Types> types;
Prices({
required this.id,
required this.desc,
required this.types,
});
Map<String, Object> toJson() => {
'id': id,
'desc': desc,
'types': types,
};
}
class Types {
final String id;
final String desc;
final List<Sizes> sizes;
Types({
required this.id,
required this.desc,
required this.sizes,
});
Map<String, Object> toJson() => {
'id': id,
'desc': desc,
'sizes': sizes,
};
}
class Sizes {
final String id;
final int stock;
final String desc;
final bool filled;
int quantity;
final double price;
Sizes({
required this.id,
required this.stock,
required this.desc,
required this.filled,
required this.quantity,
required this.price,
});
Map<String, Object> toJson() => {
'id': id,
'stock': stock,
'desc': desc,
'filled': filled,
'quantity': quantity,
'price': price,
};
}
void main() {
final product = Product(id: '1', desc: 'Some text', colors: [
Colors(id: 1, desc: '', prices: [
Prices(id: '1', desc: '', types: [
Types(id: '1', desc: '', sizes: [
Sizes(
id: '1',
stock: 5,
desc: '',
filled: true,
quantity: 2,
price: 1.0)
])
])
]),
Colors(id: 2, desc: '', prices: [
Prices(id: '1', desc: '', types: [
Types(id: '1', desc: '', sizes: [
Sizes(
id: '5',
stock: 5,
desc: '',
filled: true,
quantity: 2,
price: 1.0),
Sizes(
id: '50',
stock: 5,
desc: '',
filled: true,
quantity: 2,
price: 1.0),
])
])
])
]);
final bag = {
'colors': [
for (final colors in product.colors)
{
'id': colors.id,
'desc': colors.desc,
'sizes': [
for (final prices in colors.prices)
for (final types in prices.types) ...types.sizes
]
}
]
};
print(const JsonEncoder.withIndent(' ').convert(bag));
}
Output:
{
"colors": [
{
"id": 1,
"desc": "",
"sizes": [
{
"id": "1",
"stock": 5,
"desc": "",
"filled": true,
"quantity": 2,
"price": 1.0
}
]
},
{
"id": 2,
"desc": "",
"sizes": [
{
"id": "5",
"stock": 5,
"desc": "",
"filled": true,
"quantity": 2,
"price": 1.0
},
{
"id": "50",
"stock": 5,
"desc": "",
"filled": true,
"quantity": 2,
"price": 1.0
}
]
}
]
}
A trick here is that Dart will call object inside a structure returned from another toJson() call. So e.g. Product.toJson returns a Map<String, Object> which contains a list of colors. Dart are then calling the toJson() on each of these colors and so on.
This should help you, it's better to convert to json when you have maps, so you need to convert the class and it's subclasses to maps, and in the end it will be simple to convert to json.
Product class to map:
class Product {
final String id;
final String desc;
final List<Colors> colors;
Product(this.id, this.desc, this.colors);
Map toMap() {
return {
'id': this.id,
'desc': this.desc,
'colors': this.colors.map((color) => color.toMap()).toList(),
};
}
}
Colors class to map:
class Colors {
final String id;
final String desc;
final List<Sizes> sizes;
Colors(this.id, this.desc, this.sizes);
Map toMap() {
return {
'id': this.id,
'desc': this.desc,
'sizes': this.sizes.map((size) => size.toMap()).toList(),
};
}
}
Sizes class to map:
class Sizes {
final String id;
final int stock;
final String desc;
final bool filled;
int quantity;
final double price;
Sizes(this.id, this.stock, this.desc, this.filled, this.quantity, this.price);
Map toMap() {
return {
'id': this.id,
'stock': this.stock,
'desc': this.desc,
'filled': this.filled,
'quantity': this.quantity,
'price': this.price,
};
}
}
Result:
Product product = Product(...);
Map map = product.toMap();
String json = jsonEncode(map);
Related
i have my api which returns the json data, within the json there is multiple nested parts that i want to use. i have my models setup. how do i return them back to my futurebuilder and then use them i.e.
snapshot.data['media'][0].fieldname or snapshot.data['locationData'][0].fieldname.
I have change the code back so at the moment it only returns the LocationData but not the MediaData. this is the part i need help with returning all of it at the same time to use on my page.
here is what the json looks like when i get it back from the api
{
"recordsTotal": 1,
"sensordate": "2022-01-20",
"data": [
{
"id": 2,
"locationname": "The Old Man of Storr",
"description": "",
"shortdescription":"",
"latitude": "55.9486",
"longitude": " -3.1910",
"mainimageurl": "",
"road": "",
"addressline1": "",
"addressline2": "",
"town": "",
"county": "",
"postcode": "",
"areaid": 2,
"headerimageid": 450,
"carparkcapacity": 100,
"title": "Old Town",
"originalfilename": "OldTown.jpg",
"ext": "jpg",
"alttext": "Old Town",
"savelocation": "/library/images/locations/",
"filename": "cd8d5c511f3b64758238e75c1aa7c84d"
}
],
"media": [
{
"locationid": 2,
"mediaid": 32,
"title": "Old Town History",
"systemfilename": "/library/media/64c8ba08a781ef8b8b2a08c62d0427b6.mp3",
"transcriptionnotes": "Transcription of media file",
"mediatype": "audio",
"originalfilename": "oldtown.mp3",
"locationname": "Old Town"
}
]
}
//This is my 2 models
class LocationData {
final int id;
final String locationname;
final String description;
final String shortdescription;
final double latitude;
final double longitude;
final String mainimageurl;
final String imagefilename;
final String imagelocation;
final String imageext;
final int carparkcapacity;
final int areaid;
LocationData(
{required this.id,
required this.locationname,
required this.description,
required this.carparkcapacity,
required this.areaid,
required this.imageext,
required this.imagefilename,
required this.imagelocation,
required this.latitude,
required this.longitude,
required this.mainimageurl,
required this.shortdescription,
});
factory LocationData.fromJson(json) => LocationData(
locationname: json['locationname'],
id: json['id'] == null ? 0 : json["id"],
latitude: double.parse(json['latitude']),
longitude: double.parse(json['longitude']),
areaid: json['areaid'] == null ? 0 : json["areaid"],
description: json['description'] == null
? 'Welcome to Skye'
: json["description"],
shortdescription: json['shortdescription'] == null
? 'Welcome'
: json["shortdescription"],
imageext: json['ext'] == null ? 'jpg' : json["ext"],
carparkcapacity:
json['carparkcapacity'] == null ? 0 : json["carparkcapacity"],
imagefilename:
json['filename'] == null ? 'logo' : json["filename"],
imagelocation: json['savelocation'] == null
? '/assets/imgs/'
: json["savelocation"],
mainimageurl: json['mainimageurl'] == null
? '/assets/imgs/logo.jpg'
: json["mainimageurl"],
);
}
//Similar to above
class MediaData{}
//Getting the data
class LocationDataApi {
static Future<List<LocationData>> getLocationData(
String locationName) async {
final hotspotLocationsURL =
'${config.apiUrl}/locations.php?action=get_location&location=' +
locationName;
try {
final response = await http.get(Uri.parse(hotspotLocationsURL));
if (response.statusCode == 200) {
final body = json.decode(response.body);
//Returned Data
return body['data'].map<LocationData>(LocationData.fromJson).toList();
} else {
throw 'Error Retrieving Data';
}
} catch (e) {
if (kDebugMode) {
print(e);
}
// If the server did not return a 200 OK response,
// then throw an exception.
throw Exception('Failed to load Location Data');
}
}
}
on my page
class _AlreadyHereState extends State<AlreadyHere> {
late Future<List<LocationData>> _locationData;
}
....other code
FutureBuilder(
future: _locationData,
builder: (BuildContext context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(child: CircularProgressIndicator());
} else if (snapshot.error != null) {
return const Center(child: Text('an error occured!'));
} else {
//this part how do i get the data? snapshot.data['media'][0].fieldname doesnt work/
for starters, you can change your model to look this
// To parse this JSON data, do
//
// final someClass = someClassFromJson(jsonString);
import 'package:meta/meta.dart';
import 'dart:convert';
class SomeClass {
SomeClass({
required this.recordsTotal,
required this.sensordate,
required this.data,
required this.media,
});
final int recordsTotal;
final DateTime sensordate;
final List<Datum> data;
final List<Media> media;
factory SomeClass.fromRawJson(String str) => SomeClass.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory SomeClass.fromJson(Map<String, dynamic> json) => SomeClass(
recordsTotal: json["recordsTotal"],
sensordate: DateTime.parse(json["sensordate"]),
data: List<Datum>.from(json["data"].map((x) => Datum.fromJson(x))),
media: List<Media>.from(json["media"].map((x) => Media.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"recordsTotal": recordsTotal,
"sensordate": "${sensordate.year.toString().padLeft(4, '0')}-${sensordate.month.toString().padLeft(2, '0')}-${sensordate.day.toString().padLeft(2, '0')}",
"data": List<dynamic>.from(data.map((x) => x.toJson())),
"media": List<dynamic>.from(media.map((x) => x.toJson())),
};
}
class Datum {
Datum({
required this.id,
required this.locationname,
required this.description,
required this.shortdescription,
required this.latitude,
required this.longitude,
required this.mainimageurl,
required this.road,
required this.addressline1,
required this.addressline2,
required this.town,
required this.county,
required this.postcode,
required this.areaid,
required this.headerimageid,
required this.carparkcapacity,
required this.title,
required this.originalfilename,
required this.ext,
required this.alttext,
required this.savelocation,
required this.filename,
});
final int id;
final String locationname;
final String description;
final String shortdescription;
final String latitude;
final String longitude;
final String mainimageurl;
final String road;
final String addressline1;
final String addressline2;
final String town;
final String county;
final String postcode;
final int areaid;
final int headerimageid;
final int carparkcapacity;
final String title;
final String originalfilename;
final String ext;
final String alttext;
final String savelocation;
final String filename;
factory Datum.fromRawJson(String str) => Datum.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory Datum.fromJson(Map<String, dynamic> json) => Datum(
id: json["id"],
locationname: json["locationname"],
description: json["description"],
shortdescription: json["shortdescription"],
latitude: json["latitude"],
longitude: json["longitude"],
mainimageurl: json["mainimageurl"],
road: json["road"],
addressline1: json["addressline1"],
addressline2: json["addressline2"],
town: json["town"],
county: json["county"],
postcode: json["postcode"],
areaid: json["areaid"],
headerimageid: json["headerimageid"],
carparkcapacity: json["carparkcapacity"],
title: json["title"],
originalfilename: json["originalfilename"],
ext: json["ext"],
alttext: json["alttext"],
savelocation: json["savelocation"],
filename: json["filename"],
);
Map<String, dynamic> toJson() => {
"id": id,
"locationname": locationname,
"description": description,
"shortdescription": shortdescription,
"latitude": latitude,
"longitude": longitude,
"mainimageurl": mainimageurl,
"road": road,
"addressline1": addressline1,
"addressline2": addressline2,
"town": town,
"county": county,
"postcode": postcode,
"areaid": areaid,
"headerimageid": headerimageid,
"carparkcapacity": carparkcapacity,
"title": title,
"originalfilename": originalfilename,
"ext": ext,
"alttext": alttext,
"savelocation": savelocation,
"filename": filename,
};
}
class Media {
Media({
required this.locationid,
required this.mediaid,
required this.title,
required this.systemfilename,
required this.transcriptionnotes,
required this.mediatype,
required this.originalfilename,
required this.locationname,
});
final int locationid;
final int mediaid;
final String title;
final String systemfilename;
final String transcriptionnotes;
final String mediatype;
final String originalfilename;
final String locationname;
factory Media.fromRawJson(String str) => Media.fromJson(json.decode(str));
String toRawJson() => json.encode(toJson());
factory Media.fromJson(Map<String, dynamic> json) => Media(
locationid: json["locationid"],
mediaid: json["mediaid"],
title: json["title"],
systemfilename: json["systemfilename"],
transcriptionnotes: json["transcriptionnotes"],
mediatype: json["mediatype"],
originalfilename: json["originalfilename"],
locationname: json["locationname"],
);
Map<String, dynamic> toJson() => {
"locationid": locationid,
"mediaid": mediaid,
"title": title,
"systemfilename": systemfilename,
"transcriptionnotes": transcriptionnotes,
"mediatype": mediatype,
"originalfilename": originalfilename,
"locationname": locationname,
};
}
and then inside FutureBuilder use like this
FutureBuilder(
future: _locationData,
// Add <T> to the Asyncsnapshot class
builder: (BuildContext context, AsyncSnapshot<SomeClass> snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(child: CircularProgressIndicator());
} else if (snapshot.error != null) {
return const Center(child: Text('an error occured!'));
} else {
print(snapshot.data.data[0].longitude);
print(snapshot.data.media[0].title);
}
OrderItem Model Class:
This is my OrderItem Model Class which contains a CartItem Map as I am trying to Parse this I am getting error "type 'List' is not a subtype of type 'Map<String, dynamic>'"
import 'package:flutter/cupertino.dart';
import 'package:practice_app/models/shippingAdress.dart';
import 'package:practice_app/providers/cart_provider.dart';
class OrderItem with ChangeNotifier {
final String? id;
final String? orderNo;
final DateTime? date;
final String? paymentMethod;
final ShippingAdress? shippingAdress;
final Map<String, CartItem>? cartItem;
final int? price;
OrderItem({
this.id,
this.orderNo,
this.date,
this.paymentMethod,
this.shippingAdress,
this.cartItem,
this.price,
});
factory OrderItem.fromJson(Map<String, dynamic> json) {
print('Json:');
print(json);
//tempitems
final json1 = json['order'];
Map<String, CartItem> dd = {};
final temp = CartItem.fromJson(json['order']) as Map<String, CartItem>;
final tempadd = ShippingAdress.fromJson(json['shippingAddress']) as ShippingAdress;
//final map = Map<String, CartItem>.from(temp);
print("printing temp items");
print(temp);
print("temp address");
//print(tempadd);
return OrderItem(
id: json['ProductID'].toString(),
orderNo: json['OrderNO'] ?? '',
date: json['Date'] ?? DateTime.now(),
paymentMethod: json['paymentMethod'] ?? 0,
shippingAdress: tempadd,
cartItem: temp,
price: json["price"] ?? '');
}
CartItem Model Class:
Here is the fromJson Method Define for CartItem.
import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
class CartItem {
String? id;
String? plantId;
String? title;
num? price;
int? quantity;
String? imageAssets;
String? size;
Color? color;
CartItem({
this.id,
this.plantId,
this.title,
this.price,
this.quantity,
this.imageAssets,
this.size,
this.color,
});
factory CartItem.fromJson(Map<String, dynamic> json) {
return CartItem(
id: json['id'] as String,
plantId: json['plantId'] as String,
title: json['title'] as String,
price: json['price'] as int,
quantity: json['quantity'] as int,
imageAssets: json['imageAsset'] as String,
size: json['size'] as String,
color: json['color'] ?? Colors.green[400] as Color,
);
}
Map toJson() => {
'id': this.id,
'plantId': this.plantId,
'title': this.title,
'price': this.price,
'quantity': this.quantity,
'imageAsset': this.imageAssets,
'size': this.size,
'color': this.color,
};
}
class Cart with ChangeNotifier {
Map<String, CartItem> _item = {};
Map<String, CartItem> get items {
return {..._item};
}
List<CartItem> get cartitem {
return [..._item.values.toList()];
}
int get itemCount {
return _item.length;
}
void emptyCart() {
_item.clear();
notifyListeners();
}
CartItem findById(String id) {
return _item.values.toList().firstWhere((element) => element.id == id);
}
double get totalAmount {
double total = 0.0;
_item.forEach((key, cartItem) {
total += cartItem.price! * cartItem.quantity!;
});
return total;
}
void removeItem(String productId) {
_item.remove(productId);
notifyListeners();
}
void updateCart(String id, CartItem newCart) {
// try {
if (_item.containsKey(id)) {
_item.update(
id,
(value) => CartItem(
plantId: newCart.plantId,
id: newCart.id,
title: newCart.title,
price: newCart.price,
quantity: newCart.quantity,
imageAssets: newCart.imageAssets,
size: newCart.size,
color: newCart.color,
),
);
}
notifyListeners();
// final SharedPreferences prefs = await SharedPreferences.getInstance();
// final cartData = json.encode(
// {
// _item,
// },
// );
// prefs.setString('CartData', cartData);
// } catch (error) {
// throw error;
// }
}
Future<void> addItem(String plantId, String quantity, String title,
double price, String image, String size, Color color) async {
int quantityy = quantity == '' ? 1 : int.parse(quantity);
String sizee = size == 'Small'
? 'Small'
: size == 'Large'
? 'Large'
: size == 'Extra Large'
? 'Extra Large'
: '';
try {
if (_item.containsKey(plantId)) {
//change Quantity
_item.update(
plantId,
(existingCartItem) => CartItem(
plantId: plantId,
id: existingCartItem.id,
title: existingCartItem.title,
price: existingCartItem.price,
imageAssets: existingCartItem.imageAssets,
quantity: existingCartItem.quantity! + quantityy,
size: sizee,
color: color,
),
);
} else {
_item.putIfAbsent(
plantId,
() => CartItem(
plantId: plantId,
id: DateTime.now().toString(),
title: title,
price: price,
imageAssets: image,
quantity: quantityy,
size: sizee,
color: color,
),
);
}
print(plantId);
notifyListeners();
final SharedPreferences prefs = await SharedPreferences.getInstance();
//print(${cartitem.first.});
final cartData = jsonEncode(
{
'cartItem': _item.toString(),
},
);
prefs.setString('CartData', cartData);
print(cartData);
print('Shared done');
} catch (error) {
throw error;
}
}
Future<bool> tryAutoFillCart() async {
final perfs = await SharedPreferences.getInstance();
if (!perfs.containsKey('CartData')) {
return false;
}
final fetchCartData = perfs.getString('CartData');
final extractedCartData =
jsonDecode(fetchCartData!) as Map<String, dynamic>;
_item = extractedCartData['cartItem'] as Map<String, CartItem>;
notifyListeners();
return true;
}
}
API DATA RESPONSE:
This is my Api data response I'm trying to parse specifically the order.
{
"StatusCode": 200,
"StatusMessage": "success",
"ProductID": 20,
"orderNO": 20,
"Date": null,
"paymentMethod": "Visa",
"shippingAddress": {
"ID": "20",
"FullName": "Ali",
"ShippingAddress": "Stadium Road"
},
"order": [
{
"id": "p8",
"plantId": "3",
"title": "Ali",
"imageAsset": "assets/images/plant3.png",
"price": 80,
"size": "Small",
"color": null,
"quantity": 4
},
{
"id": "p8",
"plantId": "3",
"title": "IQBAL",
"imageAsset": "assets/images/plant2.png",
"price": 80,
"size": "Small",
"color": null,
"quantity": 4
}
],
"price": 1500,
"Message": null
}
Error
Error I am getting trying to parse
I want to deserialize some JSON data that contains a list of article information
{
"data": [
{
"id": 1,
"title": "First article",
"createdDate": "2022-03-20T11:46:00",
"content": "Markdown content",
"author": 1,
"category": 1
},
{
"id": 2,
"title": "Second article",
"createdDate": "2022-03-20T11:46:00",
"content": "Markdown content",
"author": 1,
"category": 1
}
]
}
No matter what the request is, the top level will have a key called data
So, I created a generic class called Entry
import 'package:json_annotation/json_annotation.dart';
part 'Entry.g.dart';
#JsonSerializable(genericArgumentFactories: true)
class Entry<TData> {
Entry(this.data);
TData data;
factory Entry.fromJson(Map<String, dynamic> json,TData Function(dynamic json) fromJsonTData) => _$EntryFromJson(json,fromJsonTData);
Map<String, dynamic> toJson(Object? Function(TData value) toJsonTData) => _$EntryToJson(this,toJsonTData);
}
And for an article, I created a class call NovelData
import 'dart:convert';
import 'dart:core';
import 'package:json_annotation/json_annotation.dart';
import 'Entry.dart';
part 'NovelData.g.dart';
#JsonSerializable(genericArgumentFactories: true)
class NovelData {
NovelData(this.id, this.title, this.createdDate, this.content, this.author, this.category);
int id;
String title;
String createdDate;
String content;
int author;
int category;
factory NovelData.fromJson(Map<String, dynamic> json) =>
_$NovelDataFromJson(json);
Map<String, dynamic> toJson() => _$NovelDataToJson(this);
}
Now, if I want to use the type like Entry<List<Novel>>> to deserialize the above JSON data, what should I do?
You can access them through the full path to the data.
Full path to your data: Map => key data => Array => Array index => Map
{}.data.[].0.{}
It only takes one class.
import 'package:fast_json/fast_json_selector.dart' as parser;
void main() async {
final path = '{}.data.[].0.{}';
final pathLevel = path.split('.').length;
final items = <Novel>[];
void select(parser.JsonSelectorEvent event) {
if (event.levels.length == pathLevel) {
if (event.levels.join('.') == path) {
final item = Novel.fromJson(event.lastValue as Map);
items.add(item);
event.lastValue = null;
}
}
}
parser.parse(_json, select: select);
print(items.join('\n'));
}
final _json = '''
{
"data": [
{
"id": 1,
"title": "First article",
"createdDate": "2022-03-20T11:46:00",
"content": "Markdown content",
"author": 1,
"category": 1
},
{
"id": 2,
"title": "Second article",
"createdDate": "2022-03-20T11:46:00",
"content": "Markdown content",
"author": 1,
"category": 1
}
]
}''';
class Novel {
final int id;
final String title;
Novel({required this.id, required this.title});
#override
String toString() {
return title;
}
static Novel fromJson(Map json) {
return Novel(
id: json['id'] as int,
title: json['title'] as String,
);
}
}
Output:
First article
Second article
You can get the data before adding it to the list. The result is no different. Just a different path to the data.
void main() async {
final path = '{}.data.[].0';
final pathLevel = path.split('.').length;
final items = <Novel>[];
void select(parser.JsonSelectorEvent event) {
if (event.levels.length == pathLevel) {
if (event.levels.join('.') == path) {
final item = Novel.fromJson(event.lastValue as Map);
items.add(item);
event.lastValue = null;
}
}
}
parser.parse(_json, select: select);
print(items.join('\n'));
}
This event follows the object creation event (at a lower event level):
JsonHandlerEvent.endObject => JsonHandlerEvent.element
You can get the data after adding it to the list. But it won't be as efficient.
void main() async {
final path = '{}.data.[]';
final pathLevel = path.split('.').length;
final items = <Novel>[];
void select(parser.JsonSelectorEvent event) {
if (event.levels.length == pathLevel) {
if (event.levels.join('.') == path) {
final list = event.lastValue as List;
items.addAll(list.map((e) => Novel.fromJson(e as Map)));
list.clear();
}
}
}
parser.parse(_json, select: select);
print(items.join('\n'));
}
JsonHandlerEvent.endObject => JsonHandlerEvent.element => JsonHandlerEvent.endArray
Or even from property data. Very inefficient because all data is stored in memory.
void main() async {
final path = '{}.data';
final pathLevel = path.split('.').length;
final items = <Novel>[];
void select(parser.JsonSelectorEvent event) {
if (event.levels.length == pathLevel) {
if (event.levels.join('.') == path) {
final list = event.lastValue as List;
items.addAll(list.map((e) => Novel.fromJson(e as Map)));
event.lastValue = null;
}
}
}
parser.parse(_json, select: select);
print(items.join('\n'));
}
JsonHandlerEvent.endObject => JsonHandlerEvent.element => JsonHandlerEvent.endArray => JsonHandlerEvent.endKey
I won't even write about the last level. There is no point in such an inefficient way. However, and in the previous one, too.
JsonHandlerEvent.endObject => JsonHandlerEvent.element => JsonHandlerEvent.endArray => JsonHandlerEvent.endKey => JsonHandlerEvent.endObject
There is a website which automatically generates all needed code from json. Here is example:
// To parse this JSON data, do
//
// final entry = entryFromJson(jsonString);
import 'dart:convert';
Entry entryFromJson(String str) => Entry.fromJson(json.decode(str));
String entryToJson(Entry data) => json.encode(data.toJson());
class Entry {
Entry({
this.data,
});
List<Datum> data;
factory Entry.fromJson(Map<String, dynamic> json) => Entry(
data: List<Datum>.from(json["data"].map((x) => Datum.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"data": List<dynamic>.from(data.map((x) => x.toJson())),
};
}
class Datum {
Datum({
this.id,
this.title,
this.createdDate,
this.content,
this.author,
this.category,
});
int id;
String title;
DateTime createdDate;
String content;
int author;
int category;
factory Datum.fromJson(Map<String, dynamic> json) => Datum(
id: json["id"],
title: json["title"],
createdDate: DateTime.parse(json["createdDate"]),
content: json["content"],
author: json["author"],
category: json["category"],
);
Map<String, dynamic> toJson() => {
"id": id,
"title": title,
"createdDate": createdDate.toIso8601String(),
"content": content,
"author": author,
"category": category,
};
}
you can try my jsonize package, it will handle any of your TData classes wherever they are in your Entry data list
import 'package:jsonize/jsonize.dart';
abstract class TData {}
class Entry implements Jsonizable {
Entry({
required this.data,
});
factory Entry.empty() => Entry(data: []);
List<TData> data;
#override
String get jsonClassCode => "Entry";
#override
Entry fromJson(json) => Entry(data: List<TData>.from(json["data"]));
#override
Map<String, dynamic> toJson() => {"data": data};
}
class NovelData extends TData implements Jsonizable {
NovelData({
required this.id,
required this.title,
required this.createdDate,
required this.content,
required this.author,
required this.category,
});
factory NovelData.empty() => NovelData(
id: 0,
title: "",
createdDate: DateTime(0),
content: "",
author: 0,
category: 0);
int id;
String title;
DateTime createdDate;
String content;
int author;
int category;
#override
String get jsonClassCode => "NovelData";
#override
NovelData fromJson(json) => NovelData(
id: json["id"],
title: json["title"],
createdDate: json["createdDate"],
content: json["content"],
author: json["author"],
category: json["category"],
);
#override
Map<String, dynamic> toJson() => {
"id": id,
"title": title,
"createdDate": createdDate,
"content": content,
"author": author,
"category": category,
};
}
main() {
Jsonize.registerClass(Entry.empty());
Jsonize.registerClass(NovelData.empty());
NovelData novel1 = NovelData(
id: 1,
title: "First article",
createdDate: DateTime.now(),
content: "Markdown content",
author: 1,
category: 1);
NovelData novel2 = NovelData(
id: 2,
title: "Second article",
createdDate: DateTime.now(),
content: "Markdown content",
author: 1,
category: 1);
Entry myEntry = Entry(data: [novel1, novel2]);
String myEntryJson = Jsonize.toJson(myEntry);
print(myEntryJson);
Entry entryBackToLife = Jsonize.fromJson(myEntryJson);
print(entryBackToLife);
}
jsonize can do more like handling enums. In your case benefits are:
DateTime serialization is handled by jsonize, you don not need to transform it
You can derive new classes from TData and put them into your Entry, jsonize will handle them and automatically transform it back to the original class
This is probably going to be a stupid question but I have a problem to understand how fromJson and toJson works.
In this case if I use a List I do like that:
class DataPerDaysInfo{
List<Product>? products;
DataPerDaysInfo({required this.products});
factory DataPerDaysInfo.fromJson(Map<String, dynamic> json) => DataPerDaysInfo(
products : json["products"] == null ? null: List<Product>.from(json["products"].map((x) => Product.fromJson(x))));
Map<String, dynamic> toJson() =>
{
"products": products == null
? null
: List<dynamic>.from(products!.map((x) => x.toJson())),
};
}
but if I need to use a map how can I do it?
class DataPerDaysInfo{
Map<String, List<Product>> mapper;
DataPerDaysInfo({required this.mapper});
}
Without having a json string given. It is hard to guess. But maybe this implementation helps you a little:
import 'dart:convert';
void main() {
var dpdi = DataPerDaysInfo.fromJson(jsonDecode(json));
print(dpdi.toJson());
}
final String json = '''
{
"catalog1": [
{"id": 1, "name": "first"},
{"id": 2, "name": "second"}
],
"catalog2": [
{"id": 1, "name": "first"},
{"id": 2, "name": "second"}
]
}
''';
class DataPerDaysInfo {
Map<String, List<Product>> mapper = {};
DataPerDaysInfo.fromJson(Map<String, dynamic> json) {
json.forEach((key, value) => mapper[key] = value
.map((val) => Product.fromJson(val))
.cast<Product>()
.toList(growable: false));
}
String toJson() {
return jsonEncode(mapper);
}
}
class Product {
final int id;
final String name;
Product.fromJson(Map<String, dynamic> json)
: id = json['id'],
name = json['name'];
#override
String toString() {
return 'id: $id, name: $name';
}
Map<String, dynamic> toJson() {
return {'id': id, 'name': name};
}
}
I'm making an API to show the product image and colors,
whenever the user press on a color button, the image which is associated with that color should show using PageView.builder.
how can I make model factory for the api if this is my json?
[
{
"id": 7,
"name": "1",
"descriptions": "1",
"price": 1,
"discount": 1,
"category": "new",
"quantity": 1,
"brand": "1",
"image": "",
"created_at": "2019-08-04 09:07:25",
"updated_at": "2019-08-04 09:07:25",
"images": {
"url":"1564909645iKiw2LkoEcQIIhB4MTZJTUfwTREleWH4wEuvmRPd.png",
"color":"#fffddd"
},
"tags": [
"large"
],
"sizes": []
}
]
my model and factory:
class Response1 {
final String createdAt;
final int id;
final int quantity;
final double price;
final String name;
final String descriptions;
final String updatedAt;
final String image;
final int weight;
final List images;
final List tags;
final List sizes;
Response1(
{this.createdAt,
this.id,
this.quantity,
this.price,
this.name,
this.descriptions,
this.updatedAt,
this.image,
this.weight,
this.images,
this.tags,
this.sizes});
factory Response1.fromJson(Map<String, dynamic> json) {
return Response1(
createdAt: json['created_at'] as String,
id: json['id'] as int,
quantity: json['quantity'] as int,
price: _toDouble(json['price']),
name: json['name'] as String,
updatedAt: json['updated_at'] as String,
image: json['image'] as String,
descriptions: json['descriptions'] as String,
weight: json['weight'] as int,
images: json['images'] as List,
tags: json['tags'] as List,
sizes: json['sizes'] as List,
);
}
Map<String, dynamic> toJson() {
return {
'created_at': createdAt,
'id': id,
'quantity': quantity,
'price': price,
'name': name,
'updated_at': updatedAt,
'image': image,
'weight': weight,
'images': images,
'tags': tags,
'sizes': sizes,
};
}
}
how can I do it? is there another way?
thanks
you can use https://app.quicktype.io/ to help you simplify this aciton
the code you need please see below
// To parse this JSON data, do
//
// final response1 = response1FromJson(jsonString);
import 'dart:convert';
List<Response1> response1FromJson(String str) => new List<Response1>.from(json.decode(str).map((x) => Response1.fromJson(x)));
String response1ToJson(List<Response1> data) => json.encode(new List<dynamic>.from(data.map((x) => x.toJson())));
class Response1 {
int id;
String name;
String descriptions;
int price;
int discount;
String category;
int quantity;
String brand;
String image;
DateTime createdAt;
DateTime updatedAt;
Images images;
List<String> tags;
List<dynamic> sizes;
Response1({
this.id,
this.name,
this.descriptions,
this.price,
this.discount,
this.category,
this.quantity,
this.brand,
this.image,
this.createdAt,
this.updatedAt,
this.images,
this.tags,
this.sizes,
});
factory Response1.fromJson(Map<String, dynamic> json) => new Response1(
id: json["id"],
name: json["name"],
descriptions: json["descriptions"],
price: json["price"],
discount: json["discount"],
category: json["category"],
quantity: json["quantity"],
brand: json["brand"],
image: json["image"],
createdAt: DateTime.parse(json["created_at"]),
updatedAt: DateTime.parse(json["updated_at"]),
images: Images.fromJson(json["images"]),
tags: new List<String>.from(json["tags"].map((x) => x)),
sizes: new List<dynamic>.from(json["sizes"].map((x) => x)),
);
Map<String, dynamic> toJson() => {
"id": id,
"name": name,
"descriptions": descriptions,
"price": price,
"discount": discount,
"category": category,
"quantity": quantity,
"brand": brand,
"image": image,
"created_at": createdAt.toIso8601String(),
"updated_at": updatedAt.toIso8601String(),
"images": images.toJson(),
"tags": new List<dynamic>.from(tags.map((x) => x)),
"sizes": new List<dynamic>.from(sizes.map((x) => x)),
};
}
class Images {
String url;
String color;
Images({
this.url,
this.color,
});
factory Images.fromJson(Map<String, dynamic> json) => new Images(
url: json["url"],
color: json["color"],
);
Map<String, dynamic> toJson() => {
"url": url,
"color": color,
};
}