Store Deserialized json in a list of objects Flutter - json

I have successfully deserialized my json file. I have stored one element of the json in one object successfully , but i am getting a problem storing the objects in a list.
I tried every possible solution from the internet below you will see the trials i have made.
This is my code
class _MyHomePageState extends State<MyHomePage> {
String? _chosenSubCounty;
List<County> counties = [];
Future<String> getJson() async {
final jsonResult = await rootBundle.loadString('assets/json_files/counties.json');
List<dynamic> parsedListJson = jsonDecode(jsonResult);
print(parsedListJson[0]);//prints {name: Baringo, capital: Kabarnet, code: 30, sub_counties: [Baringo central, Baringo north, Baringo south, Eldama ravine, Mogotio, Tiaty]}
final county = County.fromJson(parsedListJson[0]);
print(county.name.toString());//prints Baringo
//trial no 1 failed
counties = parsedListJson.map((i)=>County.fromJson(i)).toList();
//trial no 2 also failed
counties = List<County>.from(parsedListJson.map((i) => County.fromJson(i)));
//trial no 3 also failed
for(int i = 0; i < parsedListJson.length; i++){
counties.add(County.fromJson(parsedListJson[i]));
}
print(counties);//prints Error: Expected a value of type 'String', but got one of type 'Null'
return jsonResult;
}
#override
void initState() {
getJson();
}
#override
Widget build(BuildContext context) {..........}
}
This is Model Class
import 'dart:convert';
List<County> countyFromJson(String str) => List<County>.from(json.decode(str).map((x) => County.fromJson(x)));
String countyToJson(List<County> data) => json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
class County {
String name;
String capital;
int code;
List subCounties;
County({
required this.name,
required this.capital,
required this.code,
required this.subCounties,
});
factory County.fromJson(Map<String, dynamic> json) {
return County(
name: json["name"],
capital: json["capital"],
code: json["code"],
subCounties: List<String>.from(json["sub_counties"])
);
}
Map<String, dynamic> toJson() => {
"name": name,
"capital": capital == null ? null : capital,
"code": code,
"sub_counties": List<dynamic>.from(subCounties.map((x) => x)),
};
}
This is the json file
[
{
"name": "Baringo",
"capital": "Kabarnet",
"code": 30,
"sub_counties": [
"Baringo central",
"Baringo north",
"Baringo south",
"Eldama ravine",
"Mogotio",
"Tiaty"
]
},
{
"name": "Bomet",
"capital": "Bomet",
"code": 36,
"sub_counties": [
"Bomet central",
"Bomet east",
"Chepalungu",
"Konoin",
"Sotik"
]
},
]

First remove comma after your 2nd json Object from your json file. Then use this code to parse your json. I've run the project and it works totally fine.
import 'package:flutter/material.dart';
import 'package:stacksolution/county_model.dart';
class FetchData extends StatefulWidget {
const FetchData({Key? key}) : super(key: key);
#override
_FetchDataState createState() => _FetchDataState();
}
class _FetchDataState extends State<FetchData> {
#override
void initState() {
// TODO: implement initState
callJson();
super.initState();
}
callJson() async {
String jsonString =
await DefaultAssetBundle.of(context).loadString('assets/county.json');
List<CountyModel> list = countyFromJson(jsonString);
print("$list");
}
#override
Widget build(BuildContext context) {
return Container();
}
}
The Model class:
import 'dart:convert';
List<CountyModel> countyFromJson(String str) => List<CountyModel>.from(
json.decode(str).map((x) => CountyModel.fromJson(x)));
String countyToJson(List<CountyModel> data) =>
json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
class CountyModel {
CountyModel({
this.name,
this.capital,
this.code,
this.subCounties,
});
String? name;
String? capital;
int? code;
List<String>? subCounties;
factory CountyModel.fromJson(Map<String, dynamic> json) => CountyModel(
name: json["name"],
capital: json["capital"],
code: json["code"],
subCounties: List<String>.from(json["sub_counties"].map((x) => x)),
);
Map<String, dynamic> toJson() => {
"name": name,
"capital": capital,
"code": code,
"sub_counties": List<dynamic>.from(subCounties!.map((x) => x)),
};
}
The Json File:
[
{
"name": "Baringo",
"capital": "Kabarnet",
"code": 30,
"sub_counties": [
"Baringo central",
"Baringo north",
"Baringo south",
"Eldama ravine",
"Mogotio",
"Tiaty"
]
},
{
"name": "Bomet",
"capital": "Bomet",
"code": 36,
"sub_counties": [
"Bomet central",
"Bomet east",
"Chepalungu",
"Konoin",
"Sotik"
]
}
]

Related

How to fetch a data from JSON in flutter?

I have a JSON file and i want to fetch the data.
here a small Json example, in this Example as we see the employee has 2 properties,
name and List of countries :
{
"Employee": [
{
"id":1
"name": "John",
"Countries": [
{
"id" :1
"country": "Uk"
},
{
"id" :2
"country": "USA"
},
{
"id" :3
"country": "Germany"
}
]
}
]
}
I used to use this method to fetch the data from JSON but the problem i faced is that this method works just with Json that doesnt have a list property :
Future<List<EmployeeModel>> fetchEmployeeList() async {
try {
final response = await http.get(Uri.parse(url));
if (response.statusCode == 200) {
var data = jsonDecode(response.body) as List;
print(data);
final employeeList = data.map((e) => EmployeeModel.fromJson(e)).toList();
return employeeList;
} else {
throw Exception("Failed to load ");
}
} catch (e) {
print(e);
rethrow;
}
}
here the model file :
import 'dart:convert';
List<EmployeeModel> employeeModelFromJson(String str) =>
List<EmployeeModel>.from(
json.decode(str).map((x) => EmployeeModel.fromJson(x)));
String employeeModelToJson(List<EmployeeModel> data) =>
json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
class EmployeeModel {
EmployeeModel({
this.id,
this.name,
this.countries,
});
int id;
String name;
List<Country> countries;
factory EmployeeModel.fromJson(Map<String, dynamic> json) => EmployeeModel(
id: json["id"],
name: json["name"],
countries: List<Country>.from(
json["Countries"].map((x) => Country.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"id": id,
"name": name,
"Countries": List<dynamic>.from(countries.map((x) => x.toJson())),
};
}
class Country {
Country({
this.id,
this.country,
});
int id;
String country;
factory Country.fromJson(Map<String, dynamic> json) => Country(
id: json["id"],
country: json["country"],
);
Map<String, dynamic> toJson() => {
"id": id,
"country": country,
};
}
var data = jsonDecode(response.body);
print(data['Employee'][0]['Countries'][0]['country'];
//Output uk
Also consider creating a model for the json so you can parse it easily and don't have to write named keys.
https://docs.flutter.dev/development/data-and-backend/json
There are some online tools like quicktype.io too
EDIT
final employeeList = data.map((e) => EmployeeModel.fromJson(e)).toList();
print(employeeList[0].countries [0].country);
//Output uk

How to deserialize generic JSON with List type in Dart

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

type 'String' is not a subtype of type 'int' of 'index' while getting media fields using the instagram API

i'm trying to get media fields from the instagram api and i'm getting this error
type 'String' is not a subtype of type 'int' of 'index'
here's Homepage.dart :
import 'package:flutter/material.dart';
import 'package:get_storage/get_storage.dart';
import 'package:insta_details/models/data.dart';
import 'package:insta_details/utils/custom_dio_mixin.dart';
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
static String id = "HomePage";
#override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> with CustomDioMixin {
bool loading = true;
bool error = false;
late Media media;
#override
void initState() {
super.initState();
getData();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: loading
? const Center(
child: CircularProgressIndicator(),
)
: error
? const Center(
child: Text('An error has occurred!'),
)
: ListView.builder(
itemBuilder: (context, index) => MediaWidget(
media: media,
),
),
),
);
}
Future<void> getData() async {
try {
final storage = GetStorage();
final token = storage.read("accessToken");
Media? media;
final response = await dio.get(
'https://graph.instagram.com/me/media?fields=id,caption,media_url,timestamp&access_token=$token',
);
print("get data response => ${response.statusCode} ${response.data}");
Media mediadata = Media.fromJson(response.data);
print(mediadata);
} catch (e) {
print("get data failed");
print(e);
setState(() {
error = true;
});
} finally {
setState(() {
loading = false;
});
}
}
}
class MediaWidget extends StatelessWidget {
final Media media;
const MediaWidget({Key? key, required this.media}) : super(key: key);
#override
Widget build(BuildContext context) {
return GridView.builder(
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
),
itemCount: 6,
itemBuilder: (context, index) {
return Image.network(media.mediaUrl);
},
);
}
}
and here data.dart :
class Media {
Media({
required this.id,
required this.caption,
required this.mediaUrl,
required this.timestamp,
});
String id;
String caption;
String mediaUrl;
String timestamp;
factory Media.fromJson(Map<String, dynamic> json) => Media(
id: json["data"]["id"] as String,
caption: json["data"]["caption"] as String,
mediaUrl: json["data"]["media_url"] as String,
timestamp: json["data"]["timestamp"] as String,
);
Map<String, dynamic> toJson() => {
"id": id,
"caption": caption,
"media_url": mediaUrl,
"timestamp": timestamp,
};
}
and the log :
I/flutter ( 5699): get data response => 200 {data: [{id: 18106429915287733, caption: cabin in the woods, media_url: https://scontent.cdninstagram.com/v/t51.29350-15/272751472_358111429123560_6575694365508668882_n.jpg?_nc_cat=100&ccb=1-5&_nc_sid=8ae9d6&_nc_ohc=0omRv4cUGtwAX8bbmC7&_nc_ht=scontent.cdninstagram.com&edm=ANo9K5cEAAAA&oh=00_AT_fqBkL5ykJXWRj7Rcy4nCnyuXEKh-8o0TX9FJkJ4dcfQ&oe=61FD881A, timestamp: 2022-01-27T11:15:07+0000}, {id: 17917394609104775, caption: Truck, media_url: https://scontent.cdninstagram.com/v/t51.29350-15/272701475_1080001635904581_1705933746471766077_n.jpg?_nc_cat=107&ccb=1-5&_nc_sid=8ae9d6&_nc_ohc=ZfSpeg7rHn4AX89PW0c&_nc_ht=scontent.cdninstagram.com&edm=ANo9K5cEAAAA&oh=00_AT_Qbj7zOH-UEzplA9mdIrCHaeb9EBBuz1RjKJclN9Q2RA&oe=61FE9898, timestamp: 2022-01-27T11:14:26+0000}, {id: 17921627228176014, caption: Gaara, media_url: https://scontent.cdninstagram.com/v/t51.29350-15/272660463_892749041374464_5507853711157520506_n.jpg?_nc_cat=101&ccb=1-5&_nc_sid=8ae9d6&_nc_ohc=va5seINOs-4AX9vOy4L&_nc_ht=scontent.cdninst
I/flutter ( 5699): get data failed
I/flutter ( 5699): type 'String' is not a subtype of type 'int' of 'index'
my JSON response :
{
"data": [
{
"id": "18106429915287733",
"caption": "cabin in the woods",
"media_type": "IMAGE",
"media_url": "https://scontent-iad3-1.cdninstagram.com/v/t51.29350-15/272751472_358111429123560_6575694365508668882_n.jpg?_nc_cat=100&ccb=1-5&_nc_sid=8ae9d6&_nc_ohc=xXGDvxMsycAAX_U_-55&_nc_ht=scontent-iad3-1.cdninstagram.com&edm=ANo9K5cEAAAA&oh=00_AT-EuNnLxrBSNirBOl1prRXlHepdhQqUjYRBEv3Zh_Ld6Q&oe=61FD881A",
"username": "parekchampl",
"timestamp": "2022-01-27T11:15:07+0000"
},
{
"id": "17917394609104775",
"caption": "Truck",
"media_type": "IMAGE",
"media_url": "https://scontent-iad3-1.cdninstagram.com/v/t51.29350-15/272701475_1080001635904581_1705933746471766077_n.jpg?_nc_cat=107&ccb=1-5&_nc_sid=8ae9d6&_nc_ohc=ZfSpeg7rHn4AX_J_eQs&_nc_ht=scontent-iad3-1.cdninstagram.com&edm=ANo9K5cEAAAA&oh=00_AT92hbhb0XK56kxC-_e8kpM6QFLazDH0TDCfdIdEIpNinw&oe=61FC9E58",
"username": "parekchampl",
"timestamp": "2022-01-27T11:14:26+0000"
},
{
"id": "17921627228176014",
"caption": "Gaara",
"media_type": "IMAGE",
"media_url": "https://scontent-iad3-1.cdninstagram.com/v/t51.29350-15/272660463_892749041374464_5507853711157520506_n.jpg?_nc_cat=101&ccb=1-5&_nc_sid=8ae9d6&_nc_ohc=va5seINOs-4AX_SB6jL&_nc_ht=scontent-iad3-1.cdninstagram.com&edm=ANo9K5cEAAAA&oh=00_AT8rviJ6wbaT0yF1Hq2VprtnQ-W0rARS5oxIr52MIhC0Rw&oe=61FD720B",
"username": "parekchampl",
"timestamp": "2022-01-27T11:13:42+0000"
},
{
"id": "18024346318348836",
"caption": "Marceline",
"media_type": "IMAGE",
"media_url": "https://scontent-iad3-1.cdninstagram.com/v/t51.29350-15/272807293_686124672409566_4991399943515126026_n.jpg?_nc_cat=106&ccb=1-5&_nc_sid=8ae9d6&_nc_ohc=JMfTMSD_1c8AX-m5WDx&_nc_ht=scontent-iad3-1.cdninstagram.com&edm=ANo9K5cEAAAA&oh=00_AT_P38eDVtcqEYL053wGPkLjhHStLCh7_fgFnCg4LcH1yA&oe=61FD1F82",
"username": "parekchampl",
"timestamp": "2022-01-27T11:13:02+0000"
},
{
"id": "17859174368680579",
"caption": "uchiha shisui",
"media_type": "IMAGE",
"media_url": "https://scontent-iad3-1.cdninstagram.com/v/t51.29350-15/272721151_749467822692662_5191995429373550055_n.jpg?_nc_cat=111&ccb=1-5&_nc_sid=8ae9d6&_nc_ohc=01A68vtgY-kAX-ux6iB&_nc_ht=scontent-iad3-1.cdninstagram.com&edm=ANo9K5cEAAAA&oh=00_AT9oWtK9VWV8j3c8Ij2YXctIpuh9sC-NJO1BLCwFObDDSA&oe=61FE0B03",
"username": "parekchampl",
"timestamp": "2022-01-27T11:12:35+0000"
},
{
"id": "17917757036265369",
"caption": "Son and Father",
"media_type": "IMAGE",
"media_url": "https://scontent-iad3-1.cdninstagram.com/v/t51.29350-15/272660947_1107548556714461_1575953024252145708_n.jpg?_nc_cat=100&ccb=1-5&_nc_sid=8ae9d6&_nc_ohc=Mzj5Wp9sv_oAX_2Z4Nv&_nc_ht=scontent-iad3-1.cdninstagram.com&edm=ANo9K5cEAAAA&oh=00_AT8Ywp3DUIemrIoCPajFvivfTG_-AWvEs2fpkngYXUN6Lg&oe=61FE17A1",
"username": "parekchampl",
"timestamp": "2022-01-27T11:11:47+0000"
}
],
"paging": {
"cursors": {
"before": "QVFIUnpEcERJTXdYRjd3SVp3MUo2U25UeWhhdlgxQ2xMY0diR2pYVFhCVl9TUUhlM1hqYllKWUpEWXJtYW5RWW41am1Lc3B4U281TU14ZAFoxSVBkMVRsZAkZAB",
"after": "QVFIUkgtUzExdDNsYzgwUFhGdnRXQlB6N0JkZATVFeU1DVkhzXzduLTF1RklpR1A5MDNMeWVEemtzdE15OVBlYmpYb29mQlVtdDJsX1N2SUcwa2ZAkc21jblZAn"
}
}
}
According to the documentation : https://developers.facebook.com/docs/instagram-basic-display-api/reference/media ,every field is a String
factory Media.fromJson(Map<String, dynamic> json) => Media(
id: json["data"]["id"] as String,
caption: json["data"]["caption"] as String,
mediaUrl: json["data"]["media_url"] as String,
timestamp: json["data"]["timestamp"] as String,
);
Or change to something like below:
factory Media.fromJson(Map<String, dynamic> json) => Media(
id: int.parse(json["data"]["id"] as String),
caption: json["data"]["caption"] as String,
mediaUrl: json["data"]["media_url"] as String,
timestamp: DateTime.parse(json["data"]["timestamp"] as String),
);
The value of your data key is a List not a Map. Here's an example:
const responseData =
{
"data":[
{
"id":"18106429915287733",
"caption":"cabin in the woods",
"media_type":"IMAGE",
"media_url":"https://scontent-iad3-1.cdninstagram.com/v/t51.29350-15/272751472_358111429123560_6575694365508668882_n.jpg?_nc_cat=100&ccb=1-5&_nc_sid=8ae9d6&_nc_ohc=xXGDvxMsycAAX_U_-55&_nc_ht=scontent-iad3-1.cdninstagram.com&edm=ANo9K5cEAAAA&oh=00_AT-EuNnLxrBSNirBOl1prRXlHepdhQqUjYRBEv3Zh_Ld6Q&oe=61FD881A",
"username":"parekchampl",
"timestamp":"2022-01-27T11:15:07+0000"
},
{
"id":"17917394609104775",
"caption":"Truck",
"media_type":"IMAGE",
"media_url":"https://scontent-iad3-1.cdninstagram.com/v/t51.29350-15/272701475_1080001635904581_1705933746471766077_n.jpg?_nc_cat=107&ccb=1-5&_nc_sid=8ae9d6&_nc_ohc=ZfSpeg7rHn4AX_J_eQs&_nc_ht=scontent-iad3-1.cdninstagram.com&edm=ANo9K5cEAAAA&oh=00_AT92hbhb0XK56kxC-_e8kpM6QFLazDH0TDCfdIdEIpNinw&oe=61FC9E58",
"username":"parekchampl",
"timestamp":"2022-01-27T11:14:26+0000"
}
]
};
void main() {
final mediaList = responseData["data"]!.map((entry) => Media.fromJson(entry))
.toList();
for (var media in mediaList) {
print(media.id);
}
}
class Media {
Media({
required this.id,
required this.caption,
required this.mediaUrl,
required this.timestamp,
});
int? id;
String caption;
String mediaUrl;
String timestamp;
factory Media.fromJson(Map<String, dynamic> json) {
return Media(
id: int.tryParse(json["id"]),
caption: json["caption"],
mediaUrl: json["media_url"],
timestamp: json["timestamp"],
);
}
Map<String, dynamic> toJson() => {
"id": id.toString(),
"caption": caption,
"media_url": mediaUrl,
"timestamp": timestamp,
};
}
On your model class id is nullable int, but you are receiving id as String.
You can typecast string to int On your Media.fromJson, while the id accept null value, if something wrong happen id will get null value.
factory Media.fromJson(Map<String, dynamic> json) => Media(
id: int.tryParse(json["data"]["id"]),
And for toJson pass id as String
Map<String, dynamic> toJson() => {
"id": id.toString(),
More about int.tryParse.

Map field into fromjson dart

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};
}
}

flutter nested json array of object parsing

Hi i am building an app and trying to parse nested array of object from an api call back and getting this error
Type String is not the sub Type of Map<String, dynamic>
Here is the model class
class Tournament {
String id;
String title;
String roomID;
String roomPass;
String map;
String type;
String date;
String time;
int joined;
String createdBy;
List<UserIds> joinedUsers;
Tournament(
{this.createdBy,
this.joinedUsers,
this.id,
this.date,
this.map,
this.roomID,
this.roomPass,
this.time,
this.title,
this.type,
this.joined});
factory Tournament.fromJson(Map<String, dynamic> json) {
var list = json['joinedUsers'] as List;
List<UserIds> userList =
list.map((data) => UserIds.fromJson(data)).toList();
return Tournament(
id: json['_id'],
title: json['title'],
roomID: json['roomId'],
roomPass: json['roomPass'],
map: json['mapType'],
type: json['type'],
date: json['date'],
time: json['time'],
joined: json['joined'],
createdBy: json['createdBy'],
joinedUsers: userList);
}
}
class UserIds {
String userId;
UserIds({this.userId});
factory UserIds.fromJson(Map<String, dynamic> parsedJson) {
return UserIds(userId: parsedJson['\$oid']);
}
}
this is the json call back i got
{
"_id": {
"$oid": "5f1c47f2c3c051d9828b1697"
},
"joinedUsers": [{
"$oid": "5f18621d6fca9d3e70a9fabe"
}, {
"$oid": "5f1a7609f7f69d2a1064e5ec"
}],
"title": "HomeComing",
"date": "20-02-2020",
"time": "8:22 Am",
"roomId": "12345",
"roomPass": "12223",
"joined": {
"$numberInt": "9"
},
"mapType": "Erangle",
"type": "Dual",
"createdBy": {
"$oid": "5f16d9bde0fd621dec10e1c5"
},
"__v": {
"$numberInt": "0"
}
}
now when i run this it gave me an error that type String is not the sub type of Map<String, dynamic>
i dont know what wrong i am doing right now
Could you try:
list.map((data) => UserIds.fromJson(JSON.parse(data)).toList();
Could be parse problems, you could log first your elements in your lambda by this to verify what it gives:
list.map((element) =>
{
console.log(data);
//UserIds.fromJson(JSON.parse(data)).toList();
});
Just check out this example that I have made for userIds:
I have taken your json locally.
import 'dart:convert';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(home: HomePage());
}
}
class UserIds {
String userId;
UserIds({this.userId});
}
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
bool _isLoading = false;
List<UserIds> userIdsList = List();
#override
void initState() {
super.initState();
getData();
}
getData() async {
String data =
await DefaultAssetBundle.of(context).loadString("json/parse.json");
Map jsonData = json.decode(data);
jsonData['joinedUsers'].forEach((item) {
item.forEach((key, value) {
print('This is the Key $key value $value');
userIdsList.add(UserIds(userId: value));
});
});
print('This is the list ${userIdsList.length}');
}
#override
Widget build(BuildContext context) {
return Scaffold(body: Text(''));
}
}