i am new to flutter, and i meet this API with complex "MAP" json. What i want is to display the list of countries with their details in flutter listview, How can i achieve that? Most of answers explain about "LIST" json.
{
"status": "Request is successful",
"message": null,
"data": {
"page": 1,
"last_page": 125,
"page_size": 2,
"countries": [
{
"id": "1",
"attributes": {
"name": "Grenada",
"code": "GD",
"subregion": "Caribbean",
"flag": "https://flagcdn.com/gd.svg",
"postalcode": "",
"latitude": "12.11666666",
"longitude": "-61.66666666",
"createdAt": "2023-01-11T22:15:40.000000Z",
"updatedAt": "2023-01-11T22:15:40.000000Z"
}
},
{
"id": "2",
"attributes": {
"name": "Malaysia",
"code": "MY",
"subregion": "South-Eastern Asia",
"flag": "https://flagcdn.com/my.svg",
"postalcode": "^(\\d{5})$",
"latitude": "2.5",
"longitude": "112.5",
"createdAt": "2023-01-11T22:15:40.000000Z",
"updatedAt": "2023-01-11T22:15:40.000000Z"
}
}
]
}
}
I found this GitHub project with these files json, modelClass Mainclass which relate with the concept but mine is has got one extra braces (map) so i do not know how to achieve the goal.
if there any suggestion or best way to code please help me.
this is how they created in model class but, but it does not work with me.
class Product {
final List<Result> results;
Product({this.results});
factory Product.fromJson(Map<String, dynamic> data) {
var list = data['data']['result'] as List;
List<Result> resultList = list.map((e) => Result.fromJson(e)).toList();
return Product(
results: resultList,
);
}
}
what i have done is
class MyStatefulWidget extends StatefulWidget {
const MyStatefulWidget({super.key});
@override
State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
}
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
var data_from_link;
getData() async {
final String link = 'myurl';
data_from_link = await http.get(Uri.parse(link), headers: {"Accept": "application/json"});
final res = jsonDecode(data_from_link.body) as Map<String, dynamic>;
final List<Country> list= (res['data']['countries'] as List<dynamic>).map((e) => Country.fromJson(e))
.toList();
}
@override
void initState() {
super.initState();
getData();
}
@override
Widget build(BuildContext context) {
final res = jsonDecode(data_from_link.body) as Map<String, dynamic>;
final List<Country> list= (res['data']['countries'] as List<dynamic>).map((e) => Country.fromJson(e))
.toList();
return ListView.builder(
itemCount: list.length,
itemBuilder: (_, i) => ListTile(
title: Text(
list![i].attributes.name,
),
subtitle: Text(list![i].attributes.code),
)
);
}
}
You can create two classes for Country
and Attribute
class Country {
const Country({required this.id, required this.attributes});
/// Creates a Country from Json map
factory Country.fromJson(Map<String, dynamic> json) => Country(
id: json['id'] as String,
attribute:
Attribute.fromJson(json['attributes'] as Map<String, dynamic>),
);
/// A description for id
final String id;
final Attribute attributes;
}
class Attribute {
const Attribute({
required this.name,
required this.code,
required this.createdAt,
required this.updatedAt,
});
/// Creates a Attribute from Json map
factory Attribute.fromJson(Map<String, dynamic> json) => Attribute(
name: json['name'] as String,
code: json['code'] as String,
createdAt: DateTime.parse(json['createdAt'] as String),
updatedAt: DateTime.parse(json['updatedAt'] as String),
);
final String name;
final String code;
final DateTime createdAt;
final DateTime updatedAt;
}
when decoding:
final res = jsonDecode(json) as Map<String, dynamic>;
final List<Country> list = (res['data']['countries'] as
List<dynamic>)
.map((e) => Country.fromJson(e))
.toList();
Thank you but how can i print or call data from country attribute after decoding because when i try something like Print (list.country.attribute.name) . I fail. My goal is to display on Listview
You can use it like this:
ListView.builder(
itemCount: list.length,
itemBuilder: (_, i) => ListTile(
title: Text(
list[i].attributes.name,
),
subtitle: Text(list[i].attributes.code),
)),
UPDATE
import 'package:flutter/material.dart';
class MyStatefulWidget extends StatefulWidget {
const MyStatefulWidget({super.key});
@override
State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
}
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
late Future<List<Country>> futureList;
Future<List<Country>?> getData() async {
final String link = 'yoururl';
final res = await http
.get(Uri.parse(link), headers: {"Accept": "application/json"});
if (response.statusCode == 200) {
final List<Country> list = (res['data']['countries'] as List<dynamic>)
.map((e) => Country.fromJson(e))
.toList();
return list;
} else {
throw Exception('Failed to fetch data');
}
}
@override
void initState() {
super.initState();
futureList = getData();
}
@override
Widget build(BuildContext context) {
return FutureBuilder(
future: futureList,
builder: (context, snapshot) {
if (snapshot.hasData) {
final list = snapshot.data;
return ListView.builder(
itemCount: list!.length,
itemBuilder: (_, i) => ListTile(
title: Text(
list![i].attributes.name,
),
subtitle: Text(list![i].attributes.code),
),
);
} else if (snapshot.hasError) {
return const Text('error fetching data');
}
return const CircularProgressIndicator();
},
);
}
}