Filtering nested JSON response in Flutter - json

Hello I have a question regarding filtering of nested json response from an API.
Suppose I have this sample JSON response from an API:
{
"results": {
"data": {
"parentName": "Vic",
"parentFamName": "Lo",
"children": [
{
"childName": "Mark",
"childCount": 2,
"grandChildren": [
{
"grandChildName": "Kent",
"grandChildAge": 4,
"isBoy": true,
},
{
"grandChildName": "Chris",
"grandChildAge": 8
"isBoy": true,
}]
},
{
"childName": "Kim",
"childCount": 3,
"grandChildren": [
{
"grandChildName": "Martin",
"grandChildAge": 6,
"isBoy": true,
},
{
"grandChildName": "Thesa",
"grandChildAge": 4
"isBoy": false,
},
{
"grandChildName": "Beck",
"grandChildAge": 2,
"isBoy": false,
}]
}]
}
}
}
then ill be decoding the response by:
final jsonResponse = jsonDecode(jsonString.body);
final parentResponse = jsonResponse['results']['data'];
But before I display it in a ListView.builder,
how do I filter the parenetResponse wherein it will only include "isBoy" = true?
like the final data response to display would be:
{
"results": {
"data": {
"parentName": "Vic",
"parentFamName": "Lo",
"children": [
{
"childName": "Mark",
"childCount": 2,
"grandChildren": [
{
"grandChildName": "Kent",
"grandChildAge": 4,
"isBoy": true,
},
{
"grandChildName": "Chris",
"grandChildAge": 8
"isBoy": true,
}]
},
{
"childName": "Kim",
"childCount": 3,
"grandChildren": [
{
"grandChildName": "Martin",
"grandChildAge": 6,
"isBoy": true,
},
]
}]
}
}
}
Thank you for any help!

First create model class to parse your json:
class ParentModel {
final String parentName;
final List<ChildrenModel> children;
ParentModel({required this.parentName, required this.children});
static ParentModel fromJson(Map<String, dynamic> json) {
var children = json['children'] as List;
return ParentModel(
parentName: json['parentName'],
children: children.map((e) => ChildrenModel.fromJson(e)).toList());
}
}
class ChildrenModel {
final int count;
final String name;
final List<GrandChildModel> grandChildren;
ChildrenModel({
required this.count,
required this.name,
required this.grandChildren,
});
static ChildrenModel fromJson(Map<String, dynamic> json) {
var grandChildren = json["grandChildren"] as List;
return ChildrenModel(
count: json['childCount'],
name: json['childName'],
grandChildren:
grandChildren.map((e) => GrandChildModel.fromJson(e)).toList());
}
}
class GrandChildModel {
final int age;
final String name;
final bool isBoy;
GrandChildModel({required this.age, required this.name, required this.isBoy});
static GrandChildModel fromJson(Map<String, dynamic> json) {
return GrandChildModel(
age: json['grandChildAge'],
name: json['grandChildName'],
isBoy: json['isBoy']);
}
}
then use this to show the boy grandChildren:
class TestParent extends StatefulWidget {
const TestParent({super.key});
#override
State<TestParent> createState() => _TestParentState();
}
class _TestParentState extends State<TestParent> {
#override
Widget build(BuildContext context) {
final parentResponse = jsonResponse['results']!['data'];
var parent = ParentModel.fromJson(parentResponse!);
return Scaffold(
appBar: AppBar(title: Text("Testing")),
body: Column(
children: [
Expanded(
child: ListView.builder(
itemCount: parent.children.length,
itemBuilder: (context, index) {
return ListView.builder(
shrinkWrap: true,
itemCount: parent.children[index].grandChildren.length,
itemBuilder: (context, i) {
var grandChild = parent.children[index].grandChildren[i];
if (grandChild.isBoy) {
return Text(grandChild.name);
} else {
return SizedBox();
}
},
);
},
),
)
],
),
);
}
}
Note that here jsonResponse is your json;
result:

Without making model classes you could simply modify the response like this:
parentResponse['children'] = parentResponse['children']
.map((child) => child
..['grandChildren'] = child['grandChildren']
.where((grandChild) => grandChild['isBoy'] as bool)
.toList())
.toList();

Related

Parsing Json data in flutter

Hi I have a json corresponding to that I need to fetch data but no data is being shown on the screen don't know why most probably Implementation is wrong
class TestScreen extends StatefulWidget {
const TestScreen({Key? key}) : super(key: key);
#override
State<TestScreen> createState() => _TestScreenState();
}
class _TestScreenState extends State<TestScreen> {
List<AppDetails> details = [];
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
elevation: 0,
backgroundColor: kBackgroundColor,
title: Text(
'Home',
style: Theme.of(context).textTheme.headline2,
),
),
body: Expanded(
child: ListView.builder(
itemCount: details.length,
itemBuilder: (context, index) {
final detail = details[index];
return buildProduct(detail);
}),
),
);
}
}
Widget buildProduct(AppDetails detail) => Column(
children: [Center(child: Text('${detail.benefits}'))],
);
Above is My Implementation
{
"name": "TestingApp",
"category": "Production",
"subcategory": "Productivity",
"imageUrl": "Testing-Banner.jpg",
"logo": "PI.png",
"description": "Testing is an application for easy & effective Inspection",
"appDetails": [{
"systemOverview": "https:url.com",
"multiDeviceSupport": [{
"label": "Multi-Device"
},
{
"label": "Multi-Lingual"
},
{
"label": "Multi-Database"
}
],
"mainFeatures": [{
"label": "Testing"
},
{
"label": "Ease"
},
{
"label": "Select failure "
},
{
"label": "Add comments & take evidence Pictures"
},
{
"label": "Send results to central system"
},
{
"label": "Search/view "
}
],
"benefits": [{
"label": "Easy & quick solution "
},
{
"label": "Go paperless "
},
{
"label": "Lower costs"
},
{
"label": "Improve quality/safety"
},
{
"label": "Configurable on hand-held devices and tablets"
},
{
"label": "Electronic notifications to corresponding personnel’s"
}
]
}]
}
Following is a json sample
I need to show all the benefits similarly all the multidevice support Or can say all the app details but in different kind of a container.
any help would be great.
is this what you want?
try this code or try on dartpad
import 'package:flutter/material.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
runApp(const MaterialApp(home: TestScreen()));
}
class TestScreen extends StatefulWidget {
const TestScreen({Key? key}) : super(key: key);
#override
State<TestScreen> createState() => _TestScreenState();
}
class _TestScreenState extends State<TestScreen> {
List<AppDetails>? details = [];
final Map<String, dynamic> json = {
"name": "TestingApp",
"category": "Production",
"subcategory": "Productivity",
"imageUrl": "Testing-Banner.jpg",
"logo": "PI.png",
"description": "Testing is an application for easy & effective Inspection",
"appDetails": [
{
"systemOverview": "https:url.com",
"multiDeviceSupport": [
{"label": "Multi-Device"},
{"label": "Multi-Lingual"},
{"label": "Multi-Database"}
],
"mainFeatures": [
{"label": "Testing"},
{"label": "Ease"},
{"label": "Select failure "},
{"label": "Add comments & take evidence Pictures"},
{"label": "Send results to central system"},
{"label": "Search/view "}
],
"benefits": [
{"label": "Easy & quick solution "},
{"label": "Go paperless "},
{"label": "Lower costs"},
{"label": "Improve quality/safety"},
{"label": "Configurable on hand-held devices and tablets"},
{"label": "Electronic notifications to corresponding personnel’s"}
]
}
]
};
#override
void initState() {
super.initState();
final data = AppDetailModel.fromJson(json);
details = data.appDetails;
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
elevation: 0,
backgroundColor: Colors.blue,
title: const Text('Home'),
),
body: SizedBox(
child: ListView.builder(
itemCount: details?.length,
itemBuilder: (context, index) {
final detail = details?[index];
return buildProduct(detail);
},
),
),
);
}
}
Widget buildProduct(AppDetails? detail) => Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: (detail?.benefits ?? []).map((e) {
final index = (detail?.benefits ?? []).indexOf(e);
return Row(
children: [
SizedBox(width: 20, child: Text('${index + 1}.')),
Text('${e.label}'),
],
);
}).toList(),
),
);
class AppDetailModel {
String? name;
String? category;
String? subcategory;
String? imageUrl;
String? logo;
String? description;
List<AppDetails>? appDetails;
AppDetailModel(
{this.name,
this.category,
this.subcategory,
this.imageUrl,
this.logo,
this.description,
this.appDetails});
AppDetailModel.fromJson(Map<String, dynamic> json) {
name = json['name'];
category = json['category'];
subcategory = json['subcategory'];
imageUrl = json['imageUrl'];
logo = json['logo'];
description = json['description'];
if (json['appDetails'] != null) {
appDetails = <AppDetails>[];
json['appDetails'].forEach((v) {
appDetails!.add(AppDetails.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['name'] = name;
data['category'] = category;
data['subcategory'] = subcategory;
data['imageUrl'] = imageUrl;
data['logo'] = logo;
data['description'] = description;
if (appDetails != null) {
data['appDetails'] = appDetails!.map((v) => v.toJson()).toList();
}
return data;
}
}
class AppDetails {
String? systemOverview;
List<Label>? multiDeviceSupport;
List<Label>? mainFeatures;
List<Label>? benefits;
AppDetails(
{this.systemOverview,
this.multiDeviceSupport,
this.mainFeatures,
this.benefits});
AppDetails.fromJson(Map<String, dynamic> json) {
systemOverview = json['systemOverview'];
if (json['multiDeviceSupport'] != null) {
multiDeviceSupport = <Label>[];
json['multiDeviceSupport'].forEach((v) {
multiDeviceSupport!.add(Label.fromJson(v));
});
}
if (json['mainFeatures'] != null) {
mainFeatures = <Label>[];
json['mainFeatures'].forEach((v) {
mainFeatures!.add(Label.fromJson(v));
});
}
if (json['benefits'] != null) {
benefits = <Label>[];
json['benefits'].forEach((v) {
benefits!.add(Label.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['systemOverview'] = systemOverview;
if (multiDeviceSupport != null) {
data['multiDeviceSupport'] =
multiDeviceSupport!.map((v) => v.toJson()).toList();
}
if (mainFeatures != null) {
data['mainFeatures'] = mainFeatures!.map((v) => v.toJson()).toList();
}
if (benefits != null) {
data['benefits'] = benefits!.map((v) => v.toJson()).toList();
}
return data;
}
}
class Label {
String? label;
Label({this.label});
Label.fromJson(Map<String, dynamic> json) {
label = json['label'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['label'] = label;
return data;
}
}

Parse Array in Object in Array in Dart / Flutter

I have a REST Service I like to consume, but I do not know how to parse that JSON to an Object.
My JSON looks like that:
[
{
"types": {
"KEYWORD": "STRING"
},
"displaynames": {
"KEYWORD": "Keyword"
},
"rows": [
{
"KEYWORD": "Test 1"
},
{
"KEYWORD": "Test 2"
}
]
}
]
That is my object I created from that:
import 'dart:convert';
List<Todo> welcomeFromJson(String str) =>
List<Todo>.from(json.decode(str).map((x) => Todo.fromJson(x)));
String welcomeToJson(List<Todo> data) =>
json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
class Todo {
Todo({
required this.types,
required this.displaynames,
required this.rows,
});
Displaynames types;
Displaynames displaynames;
List<Displaynames> rows;
factory Todo.fromJson(Map<String, dynamic> json) => Todo(
types: Displaynames.fromJson(json["types"]),
displaynames: Displaynames.fromJson(json["displaynames"]),
rows: List<Displaynames>.from(
json["rows"].map((x) => Displaynames.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"types": types.toJson(),
"displaynames": displaynames.toJson(),
"rows": List<dynamic>.from(rows.map((x) => x.toJson())),
};
}
class Displaynames {
Displaynames({
required this.keyword,
});
String keyword;
factory Displaynames.fromJson(Map<String, dynamic> json) => Displaynames(
keyword: json["KEYWORD"],
);
Map<String, dynamic> toJson() => {
"KEYWORD": keyword,
};
}
I try Loading the JSON and Display like that by using the pull_to_refresh Package.
import 'package:flutter/material.dart';
import 'package:pull_to_refresh_flutter3/pull_to_refresh_flutter3.dart';
import 'dart:convert';
import 'package:user_portal/model/todo.dart';
class TodoRoute extends StatefulWidget {
const TodoRoute({super.key});
#override
State<TodoRoute> createState() => _TodoRouteState();
}
class _TodoRouteState extends State<TodoRoute> {
late List<Todo> todoList = [];
final RefreshController refreshController =
RefreshController(initialRefresh: true);
Future<bool> fetchTodo() async {
const String jsonstr =
'[ { "types": { "KEYWORD": "STRING" }, "displaynames": { "KEYWORD": "Keyword" }, "rows": [ { "KEYWORD": "Test 1" }, { "KEYWORD": "Test 2" } ] }]';
todoList = (json.decode(jsonstr) as List)
.map((data) => Todo.fromJson(data))
.toList();
setState(() {});
return true;
}
#override
Widget build(context) {
return Scaffold(
appBar: AppBar(
title: const Text('Todo'),
),
body: SmartRefresher(
controller: refreshController,
enablePullUp: true,
onRefresh: () async {
final result = await fetchTodo();
if (result) {
refreshController.refreshCompleted();
} else {
refreshController.refreshFailed();
}
},
onLoading: () async {
final result = await fetchTodo();
if (result) {
refreshController.loadComplete();
} else {
refreshController.loadFailed();
}
},
child: ListView.separated(
scrollDirection: Axis.vertical,
itemCount: todoList.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(todoList[0].rows[index].keyword),
);
},
separatorBuilder: (context, index) => const Divider(),
),
),
);
}
}
But the Only Item I get is the Test 1 Item not the Test 2 Item and I do not know where to look further for that Problem.
try this way it's so easy...
add this method in your TOdo model
static List< Todo > fromList(json) {
List< Todo > tempList = [];
try {
json.forEach((element) {
tempList.add(Todo.fromJson(element));
});
return tempList;
} catch (e) {
return tempList;
}
}
change this function
Future<bool> fetchTodo() async {
const String jsonstr =
'[ { "types": { "KEYWORD": "STRING" },
"displaynames": { "KEYWORD": "Keyword" }, "rows": [ {
"KEYWORD": "Test 1" }, { "KEYWORD": "Test 2" }
]
}]';
Map data = json.decode(jsonstr);
todoList = Todo.fromList(data);
setState(() {});
return true;
}
Change your fetchTodo() to this:
Future<bool> fetchTodo() async {
const String jsonstr =
'[ { "types": { "KEYWORD": "STRING" }, "displaynames": { "KEYWORD": "Keyword" }, "rows": [ { "KEYWORD": "Test 1" }, { "KEYWORD": "Test 2" } ] }]';
todoList = welcomeFromJson(jsonstr);//<--- add this
setState(() {});
return true;
}
also change this in asdas class:
factory Todo.fromJson(Map<String, dynamic> json) => Todo(
types: Displaynames.fromJson(json["types"]),
displaynames: Displaynames.fromJson(json["displaynames"]),
rows: json["rows"] != null ? (json["rows"] as List).map((x) => Displaynames.fromJson(x)).toList():[],

Access up to the "model" key parameter in my listview builder for the provided json format in flutter

I want to access up to the "model" key parameter in my listview builder for the provided json format in flutter but I don't know how can I access them
I want to access the child object model
What the json will look like:
[
{
"vehicle": "roadways",
"id": "10000",
"category": {
"500": {
"id": "500",
"name": "Bike",
"icon": "http://example.com/bike.jpg",
"model": [
{
"id": "510",
"name": "Harley"
},
{
"id": "520",
"name": "Kawasaki"
}
]
},
"50": {
"id": "50",
"name": "Car",
"icon": "http://example.com/car.jpg",
}
},
},
{
"vehicle": "waterways",
"id": "20000",
"category": {
"600": {
"id": "600",
"name": "Ship",
"icon": "http://example.com/ship.jpg",
"model": [
{
"id": "610",
"name": "model_1"
},
{
"id": "520",
"name": "model_2"
}
]
},
"700": {
"id": "700",
"name": "model_3",
"icon": "http://example.com/car.jpg",
}
},
}
]
var data = jsonDecode("yourJosnString");
ListView.builder(
itemCount: data.length,
itemBuilder: (context, i) {
var data1 = data[i]["category"];
String firstKey = data1.keys.first;
var model = data1[firstKey];
return Column(
children: [
for (i = 0; i < model.length; i++) ...[
Text(
model["name"],
)
]
],
);
},
),
you should first make an object for this json, like this:
class Vehicle {
final String name;
final VehicleCategory category;
Vehicle({#required this.name, #required this.category});
static List<Vehicle> fromJson(List _list) {
List<Vehicle> result = [];
for (var item in _list) {
var address = Vehicle(
name: item['id'] as String,
category: VehicleCategory.fromJson(
item['category']['500'] as Map<String, Object> ?? {}),
);
result.add(address);
}
return result;
}
}
class VehicleCategory {
final String name;
final String icon;
final List<VehicleModel> model;
VehicleCategory(
{#required this.name, #required this.icon, #required this.model});
static VehicleCategory fromJson(Map<String, Object> _json) {
return VehicleCategory(
name: _json['name'] as String ?? '',
icon: _json['icon'] as String ?? '',
model:
VehicleModel.fromJson(_json['model'] as List ?? []));
}
}
class VehicleModel {
final String name;
final String id;
VehicleModel({#required this.name, #required this.id});
static List<VehicleModel> fromJson(List _list) {
List<VehicleModel> result = [];
for (var item in _list) {
var address = VehicleModel(
name: item['name'] as String,
id: item['id'] as String,
);
result.add(address);
}
return result;
}
}
then use it like this:
List<Vehicle> _list = Vehicle.fromJson(_myJson);
return ListView.builder(
itemCount: _list.length,
itemBuilder: (context, i) {
return Column(
children: [
ListView.builder(
itemCount: _list[i].category.model.length,
itemBuilder: (context, j) {
return Text(_list[i].category.model[j].name);
},
)
],
);
},
);

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.

flutter: how to parse super complex json file?

i have a super long json file to be parsed but once i fetch it in a FutureBuilder it keeps erroring that i used a null check operator on a null value, to me seems like i don't know the logic..!
here's the simplified json:
{
"city": {
"Name": "oklahoma",
"Month": [
{
"number": "01",
"day": [
{
"number": "01",
"employee": "jesse m."
},
{
"number": "02",
"employee": "john s."
},
{
"number": "03",
"name": "tyler r."
}
]
},
{
"number": "02",
"day": [
{
"number": "01",
"employee": "mat w."
},
{
"number": "02",
"employee": "may j."
},
{
"number": "03",
"name": "eric r."
}
]
}
]
}
}
note that i have one city and the json has the data of every individual days throughout the whole year
and here's the model:
// To parse this JSON data, do
//
// final company = companyFromJson(jsonString);
import 'dart:convert';
company companyFromJson(String str) => company.fromJson(json.decode(str));
String companyToJson(company data) => json.encode(data.toJson());
class company {
company({
required this.city,
});
City city;
factory company.fromJson(Map<String, dynamic> json) => company(
city: City.fromJson(json["city"]),
);
Map<String, dynamic> toJson() => {
"city": city.toJson(),
};
}
class City {
City({
required this.name,
required this.month,
});
String name;
List<Month> month;
factory City.fromJson(Map<String, dynamic> json) => City(
name: json["Name"],
month: List<Month>.from(json["Month"].map((x) => Month.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"Name": name,
"Month": List<dynamic>.from(month.map((x) => x.toJson())),
};
}
class Month {
Month({
required this.number,
required this.day,
});
String number;
List<Day> day;
factory Month.fromJson(Map<String, dynamic> json) => Month(
number: json["number"],
day: List<Day>.from(json["day"].map((x) => Day.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"number": number,
"day": List<dynamic>.from(day.map((x) => x.toJson())),
};
}
class Day {
Day({
required this.number,
required this.employee
});
String number;
String employee;
factory Day.fromJson(Map<String, dynamic> json) => Day(
number: json["number"],
employee: json["employee"]
);
Map<String, dynamic> toJson() => {
"number": number,
"employee": employee
};
}
this is the parsing method:
Future<List<Day>> getCompanyEmployee () async {
String jsonString = await DefaultAssetBundle.of(context).loadString('assets/json/OklahomaEmployee.json');
List<dynamic> result = jsonDecode(jsonString);
List<Day> Company = result.map((e) => Day.fromJson(e)).toList();
return Company;
}
this is the implementation:
FutureBuilder<List<Day>>(
future: getCompanyEmployee(),
builder: (context, snapshot) {
var itemList = snapshot.data;
return GridView.builder(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
mainAxisSpacing: 10,
crossAxisSpacing: 10,
),
itemCount: itemList!.length,
itemBuilder: (BuildContext context, index) {
var itemData = itemList[index];
return ClipRRect(
borderRadius: BorderRadius.circular(25),
child: Container(
height: 10,
color: Colors.white,
width: 10,
child: Center(
child: Column(
children: [
Text(
'employee',
style: TextStyle(fontSize: 15),
),
Text(itemData.employee),
Image.asset(
'assets/Pictures/employees.png',
height: 70,
)
],
),
),
),
);
},
);
},
)
In your FutureBuilder, you just assume the future has already completed. The point of a FutureBuilder is that it has not and you need to deal with that.
You need to account for the fact that your Futurebuilder needs to build something even if the future has not yet completed. The simplest thing to make that happen is to show a CircularProgressIndicator as long as you don't have data.
See What is a Future and how do I use it? for an example of how to do that.