Flutter parsing JSON with array - json

I have troubles with parsing a JSON file with array.
It looks like something like this:
{
"status": "200",
"addresses": [
{
"address": "Address 1"
},
{
"address": "Address 2"
}
]
}
And I tried to parse it with:
var response = jsonDecode(res.body);
print(response['addresses']['address'][0]);
print(response['addresses']['address'][1]);
But it is not working. Is there any common pattern how this should be?

That's because you're not accessing it the right way. You have a Map<String,dynamic> that has a List<Map<String,String>> for the key addresses.
If you want to access the first two elements of that list, you can do it by doing:
var response = jsonDecode(res.body);
print(response['addresses'][0]['address']);
print(response['addresses'][1]['address']);

The easiest way I have found for dealing with this is to have this website write the JSON parser for me. Simply copy / paste you JSON into provide field and choose Dart as the language:
https://app.Quicktype.io

Your best mapping the data into a class there is a useful website (created by Javier Lecuona) that generates the class for you. https://javiercbk.github.io/json_to_dart/
Here is an example:
var parsedJson = jsonDecode(json);
var addressList = ClientAddresses.fromJson(parsedJson);
print(addressList.addresses[0].address);
print(addressList.addresses[1].address);
class ClientAddresses {
String status;
List<Addresses> addresses;
ClientAddresses({this.status, this.addresses});
ClientAddresses.fromJson(Map<String, dynamic> json) {
status = json['status'];
if (json['addresses'] != null) {
addresses = new List<Addresses>();
json['addresses'].forEach((v) {
addresses.add(new Addresses.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['status'] = this.status;
if (this.addresses != null) {
data['addresses'] = this.addresses.map((v) => v.toJson()).toList();
}
return data;
}
}
class Addresses {
String address;
Addresses({this.address});
Addresses.fromJson(Map<String, dynamic> json) {
address = json['address'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['address'] = this.address;
return data;
}
}

Related

Flutter Models to get a List of string

I have a problem trying to make a special model with this JSON.
I actually need to get a list of organization and a list of projects.
I have no problem getting the list of projects since it's an array.
But to get the list of Organizations I admit I need help to do something like making a forEach "MyContexts" and save every Organizations in a list and return her. (Maybe this is not the best way)
Here is a example of the JSON :
{
"MyContexts": [
{
"Organisation": {
"ID": "xxx",
"Name": "xxx"
},
"Projects": [
{
"ID": "xxx",
"Name": "xxx"
}
]
}
]
}
To be more precise, I need a list of String because the value will be inserted in a DropdownFormField list of value.
I hope I have made it clear for you to understand, else you can ask me question.
Thank you in advance for your help.
You don't need a list of strings, you need a model from your json and list of it's objects. You need a class like this
class MyContextModel {
List<MyContexts>? myContexts;
MyContextModel({this.myContexts});
MyContextModel.fromJson(Map<String, dynamic> json) {
if (json['MyContexts'] != null) {
myContexts = <MyContexts>[];
json['MyContexts'].forEach((v) {
myContexts!.add(new MyContexts.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
if (this.myContexts != null) {
data['MyContexts'] = this.myContexts!.map((v) => v.toJson()).toList();
}
return data;
}
}
class MyContexts {
Organisation? organisation;
List<Projects>? projects;
MyContexts({this.organisation, this.projects});
MyContexts.fromJson(Map<String, dynamic> json) {
organisation = json['Organisation'] != null
? new Organisation.fromJson(json['Organisation'])
: null;
if (json['Projects'] != null) {
projects = <Projects>[];
json['Projects'].forEach((v) {
projects!.add(new Projects.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
if (this.organisation != null) {
data['Organisation'] = this.organisation!.toJson();
}
if (this.projects != null) {
data['Projects'] = this.projects!.map((v) => v.toJson()).toList();
}
return data;
}
}
class Organisation {
String? iD;
String? name;
Organisation({this.iD, this.name});
Organisation.fromJson(Map<String, dynamic> json) {
iD = json['ID'];
name = json['Name'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['ID'] = this.iD;
data['Name'] = this.name;
return data;
}
}
And then you need to make list of it, and you can show it's variables in your DropdownFormField widget like Text(object.Organisation!.name!)
I may be understanding it in the wrong way, but I am thinking the JSON contains a map, which values are {"Organisation": ..., "Projects": ...}. If that's not the case, you can stop reading and correct me now.
Let's say json is the variable containing the JSON structure of your example.
Then you can do
final orgs = json.values.map((context) => context['Organisation']).toList();
final projs = json.values.map((context) => context['Projects']).toList();
Or you can use forEach like you mentioned, which requires slightly more coding, but that's not much other than a style of preference. If you think a particular approach is more straightforward and more understandable, go for it.
A side note: usually we use for loops explicit instead of forEach.

How to assign nested json object to a datamodel and acces the properties with flutter?

I have a json book object which has these nested properties in it:
"books": [
{
"book_id": 1,
"book_name": "Harry Potter and the philosopher's stone",
"year_published": 1997,
"month_published": 6,
"week_published": 25,
},
{
"book_id": 2,
"book_name": "Harry Potter and the chamber of secrets",
"year_published": 1998,
"month_published": 7,
"week_published": 26,
},
How can i map this nested json object into datamodel and acces the mapped object's properties? Also how can i combine year_publishedand and month_published into DateTime object and acces it?
you can create a Books Model class which looks like this:
class BooksModel {
List<Books> books;
BooksModel({this.books});
BooksModel.fromJson(Map<String, dynamic> json) {
if (json['books'] != null) {
books = new List<Books>();
json['books'].forEach((v) {
books.add(new Books.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
if (this.books != null) {
data['books'] = this.books.map((v) => v.toJson()).toList();
}
return data;
}
}
class Books {
int bookId;
String bookName;
int yearPublished;
int monthPublished;
int weekPublished;
Books(
{this.bookId,
this.bookName,
this.yearPublished,
this.monthPublished,
this.weekPublished});
Books.fromJson(Map<String, dynamic> json) {
bookId = json['book_id'];
bookName = json['book_name'];
yearPublished = json['year_published'];
monthPublished = json['month_published'];
weekPublished = json['week_published'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['book_id'] = this.bookId;
data['book_name'] = this.bookName;
data['year_published'] = this.yearPublished;
data['month_published'] = this.monthPublished;
data['week_published'] = this.weekPublished;
return data;
}
}
To Assign data to it you can do that:
List booksModel= [];
booksModel = await fetchBooks();
And to show you how your fetchBooks() function should look like this can be done:
Future<List<BookModel>> fetchBooks() async {
var result = //Get your json data from Api
List jsonReponse = result.toList();
return jsonReponse.map((book) => new BookModel.fromJson(book)).toList();
}
To access that data you could use a Futurebuilder or a statemanagment solution such as Provider
an Example for Futurebuilder:
FutureBuilder<List<BookModel>>(
future: fetchBooks(),
builder: (context, AsyncSnapshot<List<BookModel>> snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return //LoadingWidget
} else {
List<BookModel> bookModelList = snapshot.data;
return Text(bookModelList.books[0].bookId);
}
},
);
With the solution above a listviewbuilder is nessecary and remember to replace 0 with index from listview.
##Note: This solution is untested and should just point you in the right direction##
Also if your JsonResponse contains more data you need to update model class.
Here is a helpful tool for generating Model classes
https://jsontodart.com/
For the DateTime feature you mentioned you might need to do like an unix time to datetime convertion Convert epoch time into timestamp flutter
In your Futurebuilder listview you can use row widget to show beside each other

Api Call With Nested Map Flutter

I am trying to make a POST call to my server that requires my data to be shaped like this:
{
"dispensary": 1,
"order_detail": [
{"product_size": 1,
"quantity": 1}
]
}
But when I make my api call, I get a 500 error on my back end saying the data looks like this:
{'{"dispensary":1,"order_detail":{"product_size":1,"quantity":1}}': ['']}
I am making the call like this:
Future getdata(dispensary, order) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
var token = prefs.getString('token');
var url = '$server/api/customer/order/getdata/?access_token=$token';
Map<String, dynamic> orderRating = {
'dispensary': dispensary,
'order_detail': order
};
await http.post(url, body: orderRating, headers: {
"Content-Type": "application/x-www-form-urlencoded"
}).then((http.Response response) {
switch (response.statusCode) {
case (200):
var responseData = json.decode(response.body);
Rate rateData =
Rate.fromJson((responseData[1]['rate_response']['rates']));
print('uploaded successfully');
print(rateData.carrierId);
break;
case (400):
print('Bad Data');
break;
case (500):
print('Failed Upload');
isUploaded = false;
break;
default:
print('Unable to get rates');
}
});
print('uploaded successfully');
}
With order_detail being a map itself of {"product_size": 1,
"quantity": 1}.
I cannot complete the call to my server. Could you tell me what I'm doing wrong
I don't get exactly what are you doing, because it's not the whole future function in it ... but I can make a guess you're trying to make a post request, where the body have some dynamic data.
What are you doing right now as far as I can see is that you're putting a map inside a map which is not what you want.
My suggestion is something like this:
Future<http.Response> postSomething(int dispensary, List<Map<String,dynamic>> order) async {
final String url = 'yoururl';
final Map<String, dynamic> body = {
'dispensary': dispensary,
'order_detail': order
};
final request = await http.post(url: url, body: convert.jsonEncode(body));
if(request.statusCode == 200) {
return something
} else {
throw Exception('Failed to send the request!!!')
}
}
Hope that my answer will help you and give a clearer idea. :)
Add the toJson methods to your objects. call toJson when generating your requests body
body: orderRating.toJson
should return the json structure as seen in this snippet
{
"dispensary": 1,
"order_detail": [
{"product_size": 1,
"quantity": 1}
]
}
class OrderRating{
int dispensary;
List<OrderDetail> orderDetail;
OrderRating({this.dispensary, this.orderDetail});
OrderRating.fromJson(Map<String, dynamic> json) {
dispensary = json['dispensary'];
if (json['order_detail'] != null) {
orderDetail = new List<OrderDetail>();
json['order_detail'].forEach((v) {
orderDetail.add(new OrderDetail.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['dispensary'] = this.dispensary;
if (this.orderDetail != null) {
data['order_detail'] = this.orderDetail.map((v) => v.toJson()).toList();
}
return data;
}
}
class OrderDetail {
int productSize;
int quantity;
OrderDetail({this.productSize, this.quantity});
OrderDetail.fromJson(Map<String, dynamic> json) {
productSize = json['product_size'];
quantity = json['quantity'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['product_size'] = this.productSize;
data['quantity'] = this.quantity;
return data;
}
}
The above code was generated using a tool found Here

How to concat two JSONObject with same key of a JSONArray in flutter

The JSON request has been split into two json object in the DataList JSONArray , because data is too large, how do i combine these two objects before i can decompress and get the values . Iam new to dart and flutter , any help would be appreciated. Thank you.
"DataList": [
{
"Data": "compressedata"
},
{
"Data": "compressedData"
}
],
here is what i have tried
class ResponseList {
List<DataList> dataList;
ResponseList({ this.DataList});
ResponseList.fromJson(Map<String, dynamic> json) {
if (json['DataList'] != null) {
DataList = new List<DataList>();
json['DataList'].forEach((v) {
dataList.add(new DataList.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> map = new Map<String, dynamic>();
if (this.DataList != null) {
map['DataList'] = this.dataList.map((v) => v.toJson()).toList();
}
return map;
}
}
class DataList {
String data;
DataList({this.data});
DataList.fromJson(Map<String, dynamic> json) {
data = json['Data'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> map = new Map<String, dynamic>();
map['Data'] = this.data;
return map;
}
}
Using the Datalist array you can do the following:
var dataList = [
{"Data": "compressedata"},
{"Data": "compressedData"}
];
var compressedData = dataList
.map((item) => item["Data"])
.reduce((value, element) => value + element);
print(compressedData); // compressedatacompressedData

How to parse a nested JSON dictionary (map)

I am trying to read a JSON code which is compatible with a Swift program into a flutter app. The structure is like this:
{
"tagDict" : {
"abc" : {
"helpHdr" : "short text1",
"helpText" : "long text1"
},
"def" : {
"helpHdr" : "short text2",
"helpText" : "long text2"
}
}
}
This creates in Swift a dictionary and shall create a map in Dart of the type {key : {helpHdr, helpText}}. A variable based on this should enable label = myVariable[tag].helpHdr, or staying with the example label = myVariable["abc"].helpHdr should assign "short text1" to label
To parse nested arrays I am using this, however, no clue how to transfer this to such a nested map.
class MyClass {
List<MySubClass> myArray;
MyClass({
this.myArray,
});
factory MyClass.fromJson(Map<String, dynamic> parsedJson){
var list = parsedJson['myArray'] as List;
List<MySubClass> listObject = list.map((i) => MySubClass.fromJson(i)).toList();
return new MyClass(
myArray: listObject,
);
}
}
class MySubClass {
int id;
String text1;
String text2;
MySubClass({
this.id,
this.text1,
this.text2,
});
factory MySubClass.fromJson(Map<String, dynamic> parsedJson){
return new MySubClass(
id: parsedJson['id'],
text1: parsedJson['text1'],
text2: parsedJson['text2'],
);
}
}
If I'm correct you want to parse your json into Data class object. If that's right then you can try this
void main() {
List<MyClass> myClassList = new List<MyClass>();
Map map = {
"tagDict": {
"abc": {"helpHdr": "short text1", "helpText": "long text1"},
"def": {"helpHdr": "short text2", "helpText": "long text2"}
}
};
map['tagDict'].forEach((key, value) {
value['id'] = key;
myClassList.add(MyClass.fromJson(value));
});
myClassList.forEach((myClass) {
print(myClass.id);
print(myClass.helpHdr);
print(myClass.helpText);
print("--------------------\n");
});
}
class MyClass {
String id;
String helpHdr;
String helpText;
MyClass({this.id, this.helpHdr, this.helpText});
MyClass.fromJson(Map<String, dynamic> json) {
id = json['id'];
helpHdr = json['helpHdr'];
helpText = json['helpText'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = this.id;
data['helpHdr'] = this.helpHdr;
data['helpText'] = this.helpText;
return data;
}
}
This is the Output:
abc
short text1
long text1
--------------------
def
short text2
long text2
--------------------
class TagRes {
TagDict tagDict;
TagRes({this.tagDict});
TagRes.fromJson(Map<String, dynamic> json) {
tagDict =
json['tagDict'] != null ? new TagDict.fromJson(json['tagDict']) : null;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
if (this.tagDict != null) {
data['tagDict'] = this.tagDict.toJson();
}
return data;
}
}
class TagDict {
Abc abc;
Abc def;
TagDict({this.abc, this.def});
TagDict.fromJson(Map<String, dynamic> json) {
abc = json['abc'] != null ? new Abc.fromJson(json['abc']) : null;
def = json['def'] != null ? new Abc.fromJson(json['def']) : null;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
if (this.abc != null) {
data['abc'] = this.abc.toJson();
}
if (this.def != null) {
data['def'] = this.def.toJson();
}
return data;
}
}
class Abc {
String helpHdr;
String helpText;
Abc({this.helpHdr, this.helpText});
Abc.fromJson(Map<String, dynamic> json) {
helpHdr = json['helpHdr'];
helpText = json['helpText'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['helpHdr'] = this.helpHdr;
data['helpText'] = this.helpText;
return data;
}
}
Based on Tipu's answer, I came up with the following code which creates the intended dictionary (or map in Dart - why couldn't they stick to standard terminology like arrays etc?!)
class TaskTags {
var tagDict = Map<String, TaskTag>();
TaskTags({
this.tagDict,
});
factory TaskTags.fromJson(Map<String, dynamic> json){
var innerMap = json['tagDict'];
var tagMap = Map<String, TaskTag>();
innerMap.forEach((key, value) {
tagMap.addAll({key: TaskTag.fromJson(value)});
});
return new TaskTags(
tagDict: tagMap,
);
}
}
class TaskTag {
String helpHdr;
String helpText;
TaskTag({
this.helpHdr,
this.helpText,
});
factory TaskTag.fromJson(Map<String, dynamic> json){
return new TaskTag(
helpHdr: json['helpHdr'],
helpText: json['helpText'],
);
}
}
This creates the following map
{"abc“ : {helpHdr: "short text1", helpText: "long text1"}, "def“ : {helpHdr: "short text2", helpText: "long text2"}}