I need to parse a json with dynamic arrays keys like this :
[{ key1:{
title: .....,
img: .....,
}, key2:{
title: .....,
img: .....,
}, }]
I know how to parse a json like this:
[
{title: .....,nbLike: ...},
{title: ...., nbLike: ...}
]
but i didn't find anything about parsing json with a dynamic key like this.
I tried this but it doesnt work.
class Event {
final String title;
final int nbLike;
Event({this.title, this.nbLike});
factory Event.fromJson(Map<String, dynamic> json) {
return Event(
title: json['title'] as String,
nbLike: json['nbLike'] as int,
);
}
}
Future<List<Event>> fetchPosts(http.Client client) async {
final response = '[{"2019-01-15":{"title":"Hey","nbLike":1}, "2019-01-
16":{"title":"Hey2","nbLike":2}}]';
return compute(parsePosts, response);
}
List<Event> parsePosts(String responseBody) {
List<Event> events = new List<Event>();
List jsonParsed = json.decode(responseBody.toString());
for (int i = 0; i < jsonParsed.length; i++) {
print('jsonParsed1 ${jsonParsed.length}');
print('jsonParsed ${jsonParsed[i]}');
events.add(new Event.fromJson(jsonParsed[i]));
}
return events;
}
I receive json from API with a key and i want to transform it to this
[{title: .....,nbLike: ...},{title: ...., nbLike: ...}]
to create a 'Event' list and display it in a card list.
It is the complete code if someone need it, Thanks KURRU HEM.
Map<String, dynamic> jsonParsed = {"2019-01-15":{"title":"Hey","nbLike":1}, "2019-01-16":{"title":"Hey2","nbLike":2}};
print(jsonParsed);
List<Event> _events = [];
List _dates = [];
jsonParsed.keys.forEach((String key){
_dates.add(key);
});
print(_dates);
for(int i=0; i<_dates.length; i++){
print(jsonParsed[_dates[i]]['title']);
print(jsonParsed[_dates[i]]['nbLike']);
final Event event = Event(
title: jsonParsed[_dates[i]]['title'],
nbLike: jsonParsed[_dates[i]]['nbLike'],
);
_events.add(event);
}
print('EVENTS --------------> $_events');
class Event {
final String title;
final int nbLike;
Event({this.title, this.nbLike});
factory Event.fromJson(Map<String, dynamic> json) {
return Event(
title: json['title'] as String,
nbLike: json['nbLike'] as int,
);
}
}
Try this.
List _events = [];
List _dates = [];
jsonParsed.keys.forEach((String key){
_dates.add(key);
});
for(int i=0; i<_dates.length; i++){
jsonParsed[_date[i]].forEach((event){
final Event event = Event(
title: jsonParsed['title'],
nbLike: jsonParsed['nbLike'],
);
_events.add(event);
});
}
Related
I have a structure of JSON response like code below (example):
{
"data": {
"items": [
{
"id": 1,
"name": "Baburiki",
"jutsu_variant": [
{
"jutsu_name": "wind release",
"damage": 1200,
},
],
},
{
"id": 2,
"name": "Zee",
"jutsu_variant": [
{
"jutsu_name": "wind release",
"damage": 1200,
},
{
"jutsu_name": "kage bunshin",
"damage": 2000,
},
],
},
],
},
}
There is a list of JSON on the items key and in that key, there is another list of JSON on the jutsu_variant key.
I have created a class model to store the JSON response like the following code
class ShinobiData {
int? id;
String? shinobiName;
JutsuVariant? jutsuVariant;
ShinobiData({
this.id,
this.shinobiName,
this.jutsuVariant,
});
factory ShinobiData.fromJson(Map<String, dynamic> json) {
return ShinobiData(
id: json['id'],
shinobiName: json['name'],
jutsuVariant: json['jutsu_variant'],
);
}
}
class JutsuVariant {
String? jutsuName;
int? jutsuDamage;
JutsuVariant({this.jutsuName, this.jutsuDamage});
factory JutsuVariant.fromJson(Map<String, dynamic> json) {
return JutsuVariant(
jutsuName: json['jutsu_name'],
jutsuDamage: json['damage'],
);
}
}
The model is working fine if there is no list on the jutsu_variant key.
This is my class for getting the API response of POST requests. (created with provider state management)
import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:http/http.dart' as http;
import 'package:learning_api/model/shinobi_model.dart';
class CatalogResponse with ChangeNotifier {
Map<String, dynamic> _map = {};
bool _error = false;
String _errorMessage = '';
List<ShinobiData> _shinobis = [];
Map<String, dynamic> get map => _map;
List<ShinobiData> get shinobis => _shinobis;
bool get error => _error;
String get errorMessage => _errorMessage;
Future<void> get fetchData async {
var _finalBody = {
'page': 1,
'items_per_page': 5,
};
String _body = const JsonEncoder().convert(_finalBody);
final response = await http.post(
Uri.parse('https://***/url'),
body: _body,
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
},
);
if (response.statusCode == 200) {
try {
_map = (jsonDecode(response.body))['data'];
List<dynamic> _listShinobi = (_map)['items'];
// this loop will add each item in the items key
for (int i = 0; i < _listShinobi.length; i++)
_shinobis.add(CatalogData.fromJson(_listItem[i]));
_error = false;
} catch (e) {
_error = true;
_errorMessage = e.toString();
_map = {};
_catalogs = [];
}
} else {
_error = true;
_errorMessage = "Error: It would be your internet connection";
_map = {};
_catalogs = [];
}
notifyListeners();
}
void initialValues() {
_map = {};
_catalogs = [];
_error = false;
_errorMessage = "";
notifyListeners();
}
}
The above code works perfectly for name and id key calling. But the problem occurs when calling the jutsu_variant key. What should I do to be able to call the value of the jutsu_name and the damage key that is in the jutsu_variant key?
Cases like this do not exist in any tutorial resources. Maybe your answer will be very valuable in the future. Thank you in advance
in your ShinobiData class
you should use List<JutsuVariant> instead of JutsuVariant
you can use json_serializable or even freezed to generate these files automatically for you
This IDE plugin JosnToDart is very convenience for me. It can generate response model just paste json to this. More we can choose nullable or not option when generate.
I have converted my JSON response in the below model:
VehicleList vehicleListFromJson(String str) =>
VehicleList.fromJson(json.decode(str));
String vehicleListToJson(VehicleList data) => json.encode(data.toJson());
class VehicleList {
VehicleList({
this.vehicles,
});
List<Vehicle> vehicles;
factory VehicleList.fromJson(Map<String, dynamic> json) => VehicleList(
vehicles: List<Vehicle>.from(
json["vehicles"].map((x) => Vehicle.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"vehicles": List<dynamic>.from(vehicles.map((x) => x.toJson())),
};
}
class Vehicle {
Vehicle({
this.vehid,
this.vehname,
this.vehdescrip,
this.vehbodyopen,
this.vehbodyopenimg,
this.vehbodyclose,
this.vehbodycloseimg,
});
String vehid;
String vehname;
String vehdescrip;
String vehbodyopen;
String vehbodyopenimg;
String vehbodyclose;
String vehbodycloseimg;
factory Vehicle.fromJson(Map<String, dynamic> json) => Vehicle(
vehid: json["vehid"],
vehname: json["vehname"],
vehdescrip: json["vehdescrip"],
vehbodyopen: json["vehbodyopen"],
vehbodyopenimg: json["vehbodyopenimg"],
vehbodyclose: json["vehbodyclose"],
vehbodycloseimg: json["vehbodycloseimg"],
);
Map<String, dynamic> toJson() => {
"vehid": vehid,
"vehname": vehname,
"vehdescrip": vehdescrip,
"vehbodyopen": vehbodyopen,
"vehbodyopenimg": vehbodyopenimg,
"vehbodyclose": vehbodyclose,
"vehbodycloseimg": vehbodycloseimg,
};
}
I make the API call like this:
Future<VehicleList> getVehicles() async {
var client = http.Client();
var vehicleModel = null;
try {
var response = await client.get(Uri.parse(Strings.getVehiclesUrl));
if (response.statusCode == 200) {
var jsonString = response.body;
var jsonMap = json.decode(jsonString);
vehicleModel = VehicleList.fromJson(jsonMap);
}
} catch (Exception) {
return vehicleModel;
}
return vehicleModel;
}
Now I need to implement a for each loop on this to check if the value for key "vehbodyopen" is "Y" or "N" and create seperate arrays or objects for them and then display them in a ListViewBuilder widget.
Im new to flutter. Im from javascript background. I solved the problem in javascript by executing for each loop in the json response and stored them in two different arrays. Im looking for the same solution in flutter and dart if possible.
for (int i = 0; i < vehicleModel.length; i++) {
if(vehicleModel[i].vehbodyopen == "Y"){
//do stuff
}else{
//do another stuff
}
}
you might try this
I found a possible solution I had to loop over the vehicles List inside the vehicleModel.
List vehList = vehicleModel.vehicles;
List openVehList = [];
List closedVehList = [];
for (var veh in vehList) {
print('executing foreach');
if (veh.vehbodyopen == "Y") {
openVehList.add(veh);
} else {
closedVehList.add(veh);
}
}
I'm trying to create a custom json and with android java I can use json object and json array, but I couldn't find them in flutter. I created list <Map <String, String >> but when I add data it changes all indexes.
List<Map<String,String>> myList=[];
Map<String,String> mymap;
for(int i=0;i<5;i++){
mymap['name']='test'+i.toString();
myList.add(mymap);
print(myList[0]);// its always change test0,test1,test2
}
for (int i=0;i<5;i++){
print(myList[i]); // its write test5,test5,test5,test5,test5 why?
}
//pass your decoded json
Map<String, dynamic> json = jsonDecode(rawJson);
List<Location> locations = List<Location>.from(json["locations"].map((x) => Location.fromJson(x)))
//Location class => days is a premitive list and can be deserialized below
class Location {
Location({
this.name,
this.days,
});
String name;
List<int> days;
factory Location.fromJson(Map<String, dynamic> json) => Location(
name: json["name"],
days: List<int>.from(json["days"].map((x) => x)),
);
Map<String, dynamic> toJson() => {
"name": name,
"days": List<dynamic>.from(days.map((x) => x)),
};
}
When you assign variable to complex class it is passing reference not value, complex classes are those that you created and built in like List, Map ... etc
In this example in your List you are adding same Map 5 times,
and because it was passing reference same Map getting changed 5 times. I hope I make sense.
Here an example.
List<Map<String,String>> myList=[];
Map<String,String> mymap; // This created one object in the current scope.
// First iteration , i = 0
mymap['name']='test'+i.toString(); // Now mymap = { name: 'test0' };
myList.add(mymap); // mylist = [mymap];
// Second iteration , i = 1
mymap['name'] = 'test'+i.toString(); // Now mymap = { name: 'test1' };. But since you already added the same mymap in myList, now myList = [{ name: 'test1' }
myList.add(mymap); // This is again adding the same mymap. So mylist = [{ name: 'test1' }, { name: 'test1' }];
I am trying to call Name and Fees from my json code
it is nested array from main array of my json the main array i can deal with it but the sub array i can't
"guideExtraServices": [
{
"Name": "Limousine",
"Fees": 100
},
{
"Name": "Bus",
"Fees": 10000
},
{
"Name": "Mini-Bus",
"Fees": 5000
}
],
And I can't do that because of the error here when iam tring to call 'Name' and 'Fees'
type 'List<ExtraServices>' is not a subtype of type 'String'
and this is my class for mapping tour guide data to use it in list view
class TourGuide{
String id;
String name;
String email;
String password;
List<ExtraServices> extraService;
TourGuide({
this.id,
this.name,
this.email,
this.password,
this.extraService,
});
TourGuide.fromJson(Map<String, dynamic> json){
List<dynamic> extra = json['guideExtraServices'];
List<ExtraServices> extraList = extra.map((i) => ExtraServices.fromJson(i)).toList();
id = json['id'].toString();
name = json['displayName'];
email = json['email'];
password = json['password'];
extraService=extraList;
}
}
and this is a Extra Services class which tour guide class depend on to get the sub array
class ExtraServices{
String name;
double fees;
ExtraServices({
this.name,
this.fees
});
ExtraServices.fromJson(Map<String, dynamic> json){
name = json['Name'];
fees = json['Fees'].toDouble();
}
}
my provider method for decode json using for api
Future<dynamic> tourGuideList() async {
_isLoading = true;
notifyListeners();
print('Starting request');
http.Response response = await http.get(Environment.tourGuide,
headers: Environment.requestHeader);
print('Completed request');
print('respond data : ${response.body}');
Map<String, dynamic> res = json.decode(response.body);
var results;
if (res['code'] == 200) {
print('start load tourguide');
_tourGuide = [];
res['message'].forEach((v) {
_tourGuide.add(new TourGuide.fromJson(v));
});
results = true;
} else {
results =
FailedRequest(code: 400, message: res['error'], status: false);
}
_isLoading = false;
notifyListeners();
return results;
}
and I don't know why I have an error and I can't fix it
I think your json should be like this in total:
{"guideExtraServices": [
{
"Name": "Limousine",
"Fees": 100
},
{
"Name": "Bus",
"Fees": 10000
},
{
"Name": "Mini-Bus",
"Fees": 5000
}
]}
Try
// To parse this JSON data, do
//
// final tourGuide = tourGuideFromJson(jsonString);
import 'dart:convert';
TourGuide tourGuideFromJson(String str) => TourGuide.fromJson(json.decode(str));
String tourGuideToJson(TourGuide data) => json.encode(data.toJson());
class TourGuide {
List<GuideExtraService> guideExtraServices;
TourGuide({
this.guideExtraServices,
});
factory TourGuide.fromJson(Map<String, dynamic> json) => TourGuide(
guideExtraServices: List<GuideExtraService>.from(json["guideExtraServices"].map((x) => GuideExtraService.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"guideExtraServices": List<dynamic>.from(guideExtraServices.map((x) => x.toJson())),
};
}
class GuideExtraService {
String name;
int fees;
GuideExtraService({
this.name,
this.fees,
});
factory GuideExtraService.fromJson(Map<String, dynamic> json) => GuideExtraService(
name: json["Name"],
fees: json["Fees"],
);
Map<String, dynamic> toJson() => {
"Name": name,
"Fees": fees,
};
}
Please try the below code :-
First Create Model :-
class GuideResponseModel {
List<GuideExtraServicesModel> guideExtraServiceList;
GuideResponseModel({
this.guideExtraServiceList
});
factory GuideResponseModel.fromJson(Map<String, dynamic> parsedJson) {
try {
List<GuideExtraServicesModel> guideExtraServiceModelList = new List();
if (parsedJson.containsKey('guideExtraServices')) {
var countryList = parsedJson['guideExtraServices'] as List;
guideExtraServiceModelList =
countryList.map((i) => GuideExtraServicesModel.fromJson(i)).toList();
}
return GuideResponseModel(
guideExtraServiceList: guideExtraServiceModelList
);
} catch (e) {
return null;
}
}
}
class GuideExtraServicesModel {
String name;
int fees;
GuideExtraServicesModel({this.name,this.fees});
factory GuideExtraServicesModel.fromJson(Map<String, dynamic> json) {
return GuideExtraServicesModel(name: json['Name'],fees: json['Fees']);
}
}
Second User the Model:-
String jsonData = '{"guideExtraServices": [{"Name": "Limousine","Fees": 100},{"Name": "Bus","Fees": 10000},{"Name": "Mini-Bus","Fees": 5000}]}';
final dynamic jsonResponse = json.decode(jsonData);
final GuideResponseModel responseModel = GuideResponseModel.fromJson(jsonResponse);
print('======${responseModel.guideExtraServiceList[0].name}----${responseModel.guideExtraServiceList[0].fees}');
Is it possible to deserialize a json with dynamic key but structured values into Map in flutter dart.
I am having a json like
{
"data" : {
"apple":{"qty":5, "price":100},
"orange":{"qty":2, "price":40},
}
}
And I want this to deserialize in flutter/dart to a model class below
class Data {
Map<String, Item> itemMap;
factory Data.fromJson(Map<String,dynamic> json) {
itemMap : json["data"]; //How to parse.
}
}
class Item {
int qty;
int price;
}
I have read through a medium blog and even this also not covering the Map part.
You need to do something like this:
//...
Future<List<ItemModel>> fetchFood() async {
List<ItemModel> foodItemsList = [];
// Get json response and parse it as a Map<String, dynamic>
final response = {
"data" : {
"apple":{"qty":5, "price":100},
"orange":{"qty":2, "price":40},
}
};
// with your real get request use this:
// final parsedJson = json.decode(response.body)['data'];
// Parsed Json have what's inside data, in case of real request look for the line above this.
final parsedJson = response['data'];
// Iterate over all fruits and create Item object from each,
// then push to a list of Item's objects to return it.
parsedJson.forEach((k,v) => foodItemsList.add(ItemModel.fromJson(v)));
return foodItemsList;
}
// Item model
class ItemModel {
int qty;
int price;
ItemModel.fromJson(Map<String,dynamic> parsedJson)
: qty = parsedJson['qty'],
price = parsedJson['price'];
}
// Then call it
main() async {
List<ItemModel> foodItemsList = await fetchFood();
//..
}
If you need the fruit name as part of the object:
//...
Future<List<ItemModel>> fetchFood() async {
List<ItemModel> foodItemsList = [];
// Get json response and parse it as a Map<String, dynamic>
final response = {
"data" : {
"apple":{"qty":5, "price":100},
"orange":{"qty":2, "price":40},
}
};
// with your real get request use this:
// final parsedJson = json.decode(response.body)['data'];
// Parsed Json have what's inside data, in case of real request look for the line above this.
final parsedJson = response['data'];
// Iterate over all fruits and create Item object from each,
// then push to a list of Item's objects to return it.
parsedJson.forEach((fruitName, fruitDetails)
=> foodItemsList.add(
ItemModel.fromJson(fruitName, fruitDetails)
)
);
return foodItemsList;
}
// Item model
class ItemModel {
String name;
int qty;
int price;
ItemModel.fromJson(String fruitName, Map<String,dynamic> parsedJson)
: name = fruitName,
qty = parsedJson['qty'],
price = parsedJson['price'];
}
// Then call it
main() async {
List<ItemModel> foodItemsList = await fetchFood();
print(foodItemsList[1].name); //orange
//..
}
I have a similar JSON with a few changes:
{
"sub_item": {
"491": ["92837|1.3|Pistachio|right", "92838|2.5|Hazelnut|left"],
"427": ["92839|7.05|Almonds|", "92840|5.12|Walnuts|"],
"396": ["92841|15|Saffron|"],
"275": ["92842|45|Caviar|"]
}
}
The keys of sub_item map (491, 427, 396, 275, and...) are dynamic(as a label not as a type) and will change per order. For example, it will be 376, 325, 493... in another order.
I want to shows both keys and values on my Flutter app and do not know how to fetch these data and show them separately. Something like this:
491:
£1.30 Pistachio
£2.50 Hazelnut
427:
£7.05 Almonds
£5.12 Walnuts
396:
£15.00 Saffron
275:
£45.00 Caviar
I used this code and it worked for me somehow but it shows only the first item of the lists. for example, it shows only Pistachio for 491 not Hazelnut and the same it shows only Almonds for 427 not Walnuts:
Future<List<ItemModel>> fetchFood() async {
List<ItemModel> foodItemsList = [];
final response = {
"sub_item": {
"491": ["92837|1.3|Pistachio|right", "92838|2.5|Hazelnut|left"],
"427": ["92839|7.05|Almonds|", "92840|5.12|Walnuts|"],
"396": ["92841|15|Saffron|"],
"275": ["92842|45|Caviar|"]
}
};
final parsedJson = response['sub_item'];
parsedJson.forEach((fruitName, fruitDetails) =>
foodItemsList.add(ItemModel.fromJson(fruitName, fruitDetails)));
return foodItemsList;
}
// Item model
class ItemModel {
String id;
String details;
ItemModel.fromJson(String subItemID, List<dynamic> subItemDetails)
: id = subItemID,
details = subItemDetails[0];
}
// Then call it
mainTest() async {
List<ItemModel> foodItemsList = await fetchFood();
for (var i = 0, j = 0;
i < foodItemsList.length;
j < foodItemsList[i].details.length, i++, j++) {
print(foodItemsList[i].id);
print(foodItemsList[j].details.split('|')[2]);
}
}
The console result:
flutter: 491
flutter: Pistachio
flutter: 427
flutter: Almonds
flutter: 396
flutter: Saffron
flutter: 275
flutter: Caviar
I found a way to achieve it. We can convert the Map from one type to another.
class Data {
Map<String, Item> itemMap;
factory Data.fromJson(Map<String,dynamic> json) {
itemMap : getMapDataFrom(json["data"]); //How to parse.
}
static Map<String, Item> getFruitItemMap(Map<String, dynamic> map) {
final Map<String, Item> fruitItemMap = HashMap();
map.forEach((name, value) {
bitItemLites[name] = Item.fromJson(value, name);
});
return bitItemLites;
}
}
class Item {
int qty;
int price;
factory Item.fromJson(Map<String,dynamic> json) {
return Item(json['qty'], json['price']);
}
}