how to return json List using flutter - flutter

i want to return json object list but i dont know how
i'm using the sample doc from flutter the
here is my code
Future<Album> fetchAlbum() async {
final response =
await http.get('https://vpic.nhtsa.dot.gov/api/vehicles/getmodelsformake/honda?format=json');
if (response.statusCode == 200) {
// If the server did return a 200 OK response,
// then parse the JSON.
return Album.fromJson(jsonDecode(response.body));
} else {
// If the server did not return a 200 OK response,
// then throw an exception.
throw Exception('Failed to load album');
}
}
class Album {
final String userId;
final List <String> Cm;
Album({this.userId, this.Cm});
factory Album.fromJson(Map<String, dynamic> json) {
return Album(
userId: json['Results'][0]['Make_Name'],
Cm: for( var i = 0 ; i < json['Count']; i++ ) {
Cm.add(json['Results'][i]['Make_Name']);
}
);
}
}
the error in Cm: for... line

In your code snippet you did not created a class to refer Results list. Try bellow code snippet.
import 'dart:convert';
import 'package:http/http.dart' as http;
Future<Album> fetchAlbum() async {
final response = await http.get(
'https://vpic.nhtsa.dot.gov/api/vehicles/getmodelsformake/honda?format=json');
if (response.statusCode == 200) {
return Album.fromJson(jsonDecode(response.body));
} else {
throw Exception('Failed to load album');
}
}
class Album {
int count;
String message;
String searchCriteria;
List<Results> results;
Album({this.count, this.message, this.searchCriteria, this.results});
Album.fromJson(Map<String, dynamic> json) {
count = json['Count'];
message = json['Message'];
searchCriteria = json['SearchCriteria'];
if (json['Results'] != null) {
results = new List<Results>();
json['Results'].forEach((v) {
results.add(new Results.fromJson(v));
});
}
}
}
class Results {
int makeID;
String makeName;
int modelID;
String modelName;
Results({this.makeID, this.makeName, this.modelID, this.modelName});
Results.fromJson(Map<String, dynamic> json) {
makeID = json['Make_ID'];
makeName = json['Make_Name'];
modelID = json['Model_ID'];
modelName = json['Model_Name'];
}
}

As the for-loop is not returning the list to the cm field, you may try using .map to do the mapping and return it.
Cm: json['Results'].map((e)=>e['Make_Name']).toList()

First off, Flutter is a Framework for Dart language, so you don't need Flutter to run that code. Run code below on console:
import 'dart:convert';
import 'package:http/http.dart' as http;
class NetService {
static Future fetchJsonData(String url) {
return
http.get(url)
.then((response) => response?.statusCode == 200 ? jsonDecode(response.body) : null)
.catchError((err) => print(err));
}
static Future<void> fetchCarModels() {
return
fetchJsonData('https://vpic.nhtsa.dot.gov/api/vehicles/getmodelsformake/honda?format=json')
.then((response) {
if (response != null) {
final Map<String, dynamic> data = response;
print('''
Count : ${data["Count"]}
Message : ${data["Message"]}
Search Criteria : ${data["SearchCriteria"]}
Models :
${(data["Results"] as List)?.fold<String>("", (m, e) => m + (e as Map<String, dynamic>)["Model_Name"] + ", ")}
'''
);
}
})
.catchError((err) => print(err));
}
}
void main(List<String> arguments) async {
await NetService.fetchCarModels();
}

Related

How to fetch an array data from API and map it to the dart object?

I'm trying to use Flutter documentation to map an array data (comes from API) to the dart object. The documentation uses a single Json object, not an array. I have the following codes:
Json data:
[
{
"channelId" : 1
"channelTitle" : "Photos"
"channelImage" : pr01.jpg
"channelLastPost" : null
"lastUpdate" : null
"userRef" : 1
},
{
"channelId" : 2
"channelTitle" : "Science"
"channelImage" : pr02.jpg
"channelLastPost" : "For test ...."
"lastUpdate" : "2023-01-03"
"userRef" : 1
}
]
ChannelListModel.dart:
class ChannelListModel {
String creator;
String? image;
String title;
String lastPost;
String lastUpdate;
ChannelListModel(
{required this.creator,
required this.image,
required this.title,
required this.lastPost,
required this.lastUpdate});
factory ChannelListModel.fromJson(Map<String, dynamic> json) {
return ChannelListModel(
creator: json['userRef'],
image: json['channelImage'],
title: json['channelTitle'],
lastPost: json['channelLastPost'],
lastUpdate: json['lastUpdate']);
}
Map<String, dynamic> toJson() {
return {
"userRef" : creator,
"channelImage" : image,
"channelTitle" : title,
"channelLastPost" : lastPost,
"lastUpdate" : lastUpdate
};
}
}
HttpRequest.dart:
class HttpServices {
Future<List<ChannelListModel>> getChannelList() async {
var url = base.BaseURL.channelListUrl;
final response = await http.get(Uri.parse(url));
if (response.statusCode == 200) {
// If the server did return a 200 OK response,
// then parse the JSON.
return List<ChannelListModel>.fromJson(jsonDecode(response.body)); //I have problem in this line
} else {
// If the server did not return a 200 OK response,
// then throw an exception.
throw Exception('Failed to load album');
}
}
}
ChannelPage.dart:
class _ChannelsState extends State<Channels> {
List<ChannelListModel> channels = [];
#override
void initState() {
super.initState();
channels = getChannelsFromHttp(); // A valid array object needs to be provided here.
}
getChannelsFromHttp()async{
var httpService = HttpServices();
var result = await httpService.getChannelList();
return result;
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: ListView.builder(
itemCount: channels.length,
itemBuilder: (context, index) =>
ChannelCard(channelModel: channels[index]),
),
);
}
}
I want to classify my codes so I decided to provided different dart files for each part. How can I fix my code?
Instead of
returnList<ChannelListModel>.fromJson(jsonDecode(response.body));
Try this code,
List<ChannelListModel> channels = [];
final res = jsonDecode(response.body);
channels.addAll(List<ChannelListModel>.from(
(res).map((x) => ChannelListModel.fromJson(x))));
return channels;
Added based on comments
#override
void initState() {
super.initState();
getChannelsFromHttp();
}
getChannelsFromHttp()async{
var httpService = HttpServices();
var result = await httpService.getChannelList();
setState((){
channels = result;
});
}
Your fromJson factory returns single ChannelListModel.
You can't use List<ChannelListModel>.fromJson. Instead iterate through List and convert each json to ChannelListModel
class HttpServices {
Future<List<ChannelListModel>> getChannelList() async {
var url = base.BaseURL.channelListUrl;
final response = await http.get(Uri.parse(url));
if (response.statusCode == 200) {
// If the server did return a 200 OK response,
// then parse the JSON.
//return List<ChannelListModel>.fromJson(jsonDecode(response.body));
final data = jsonDecode(response.body) as List<dynamic>;
return data.map((e) => ChannelListModel.fromJson(e as Map<String, dynamic>))
.toList();
} else {
// If the server did not return a 200 OK response,
// then throw an exception.
throw Exception('Failed to load album');
}
}
}
You can modify the ChannelListModel.fromJson method to handle a list of JSON objects instead of a single object. Here's one way to do it:
factory ChannelListModel.fromJson(List<dynamic> jsonList) {
return jsonList.map((json) => ChannelListModel(
creator: json['userRef'],
image: json['channelImage'],
title: json['channelTitle'],
lastPost: json['channelLastPost'],
lastUpdate: json['lastUpdate'])
).toList();
}
You can also use jsonDecode to convert the response body to a List and then use the above method to convert the list to ChannelListModel
final response = await http.get(Uri.parse(url));
if (response.statusCode == 200) {
// If the server did return a 200 OK response,
// then parse the JSON.
final jsonData = jsonDecode(response.body);
return ChannelListModel.fromJson(jsonData);
} else {
// If the server did not return a 200 OK response,
// then throw an exception.
throw Exception('Failed to load album');
}
Also, you need to update the getChannelsFromHttp function to assign the result of httpService.getChannelList() to channels variable instead of calling the function again.
#override
void initState() {
super.initState();
getChannelsFromHttp();
}
getChannelsFromHttp() async {
var httpService = HttpServices();
channels = await httpService.getChannelList();
setState(() {});
}
This should solve the problem in your code.

Unhandled Exception: type 'List<dynamic>'

I'm trying to recieve a list from a Sql Api. The catch is that i need to give an id with the query. the Widget.klant.klantId has the value i need. i know it has somthing to do with the as List<Machine> in accountpage.dart. Hope you can help me with this problem. thanks in advance.
The hole error:
accountpage.dart:
class Accountpage extends StatefulWidget {
const Accountpage(this.klant);
final Klant klant;
#override
_AccountpageState createState() => _AccountpageState();
}
class _AccountpageState extends State<Accountpage> {
_AccountpageState();
final ApiService api = ApiService();
late List<Machine> machineList;
#override initState(){
super.initState();
_getMachine();
machineList = [];
}
void _getMachine() async{
machineList = (await ApiService().getMoreMachine(widget.klant.klantId.toString())) as List<Machine>;
Future.delayed(const Duration(seconds: 1)).then((value) => setState(() {}));
}
#override
Widget build(BuildContext context) {
//Here starts the body
api_machine.dart:
Future<Machine> getMoreMachine(String klantId) async {
final response = await get(Uri.parse('$apiUrl/Select/$klantId'));
if (response.statusCode == 200) {
return Machine.fromJson(json.decode(response.body));
} else {
throw Exception('Failed to load a case');
}
}
MachineModel.dart:
List<Machine> welcomeFromJson(String str) => List<Machine>.from(json.decode(str).map((x) => Machine.fromJson(x)));
String welcomeToJson(List<Machine> data) => json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
class Machine {
Machine({
this.serienummerId,
this.serienummer,
this.bouwjaar,
this.urenstand,
this.locatie,
this.klantId,
});
int? serienummerId;
String? serienummer;
String? bouwjaar;
String? urenstand;
String? locatie;
String? klantId;
factory Machine.fromJson(Map<String, dynamic> json) => Machine(
serienummerId: json["SerienummerId"],
serienummer: json["Serienummer"],
bouwjaar: json["Bouwjaar"],
urenstand: json["Urenstand"],
locatie: json["Locatie"],
klantId: json["KlantId"],
);
Map<String, dynamic> toJson() => {
"SerienummerId": serienummerId,
"Serienummer": serienummer,
"Bouwjaar": bouwjaar,
"Urenstand": urenstand,
"Locatie": locatie,
"KlantId": klantId,
};
}
json result
[
{
"SerienummerId": 1,
"Serienummer": "-----",
"Bouwjaar": "2020",
"Urenstand": "10",
"Locatie": "---",
"KlantId": "1"
},
{
"SerienummerId": 2,
"Serienummer": "-----",
"Bouwjaar": "1998",
"Urenstand": "5010",
"Locatie": "----",
"KlantId": "1"
}
]
You are parsing the result as if it's a single Machine while it in fact is a list of machines. Process it as a list and also use the correct return type accordingly. Like
Future<List<Machine>> getMoreMachine(String klantId) async {
final response = await get(Uri.parse('$apiUrl/Select/$klantId'));
if (response.statusCode == 200) {
return List<Machine>.from(json.decode(response.body).map((x) => Machine.fromJson(x)));
} else {
throw Exception('Failed to load a case');
}
}
the return type of the method is Machine:
Future<Machine> getMoreMachine(String klantId) async {
final response = await get(Uri.parse('$apiUrl/Select/$klantId'));
if (response.statusCode == 200) {
return Machine.fromJson(json.decode(response.body));
} else {
throw Exception('Failed to load a case');
}
}
and then you cast a Machine to List :
machineList = (await ApiService()
.getMoreMachine(widget.klant.klantId.toString())) as List<Machine>;
I don't know what the JSON looks like... but if there is only one machine you could for example add it to a list like this:
machineList.add((await ApiService()
.getMoreMachine(widget.klant.klantId.toString())));
Update
Try this:
Future<List<Machine>> getMoreMachine(String klantId) async {
final response = await get(Uri.parse('$apiUrl/Select/$klantId'));
if (response.statusCode == 200) {
final jsonMachines = Machine.fromJson(json.decode(response.body));
return jsonMachines.map((item) => Machine.fromJson(item)).toList();
} else {
throw Exception('Failed to load a case');
}
}
I think this is because of in getMoreMachine you used return type as Machine actually you are assigning that value as List so make that change like this :
Future<List<Machine>> getMoreMachine(String klantId) async {
final response = await get(Uri.parse('$apiUrl/Select/$klantId'));
if (response.statusCode == 200) {
return welcomeFromJson(response.body);
} else {
throw Exception('Failed to load a case');
}
}
might be other think is you can check your API response that is not returning List of machines.

Flutter Api how to display multiple data?

This code below display one data only because i put 0 at line final Album = Album.fromJson(data[0]);. I intend to display multiple data but I don't know how to do that. any idea?
Btw i got this code from https://docs.flutter.dev/cookbook/networking/fetch-data and modified it for my personal work.
Future<Album> fetchAlbum() async {
final response =
await http.get(Uri.parse('-----'));
if (response.statusCode == 200) {
// If the server did return a 200 OK response,
// then parse the JSON.
final data = jsonDecode(response.body);
final Album = Album.fromJson(data[0]);
return Album;
} else {
// If the server did not return a 200 OK response,
// then throw an exception.
throw Exception('Failed to load Album');
}
}
If I understand your question correct, you want to return multiple Albums.
If that is the case, you can return a List of Albums and work with a foreach loop. This could look like this, for example:
Future<List<Album>> fetchAlbum() async {
List<Album> myAlbums = [];
final response =
await http.get(Uri.parse('-----'));
if (response.statusCode == 200) {
// If the server did return a 200 OK response,
// then parse the JSON.
final data = List<dynamic>.from(jsonDecode(response.body));
data.forEach((element) {
myAlbums.add(Album.fromJson(element));
});
return myAlbums;
} else {
// If the server did not return a 200 OK response,
// then throw an exception.
throw Exception('Failed to load Album');
}
You need to make a list-type Album.
Future<Album> fetchAlbum() async {
final response =
await http.get(Uri.parse('-----'));
if (response.statusCode == 200) {
// If the server did return a 200 OK response,
// then parse the JSON.
final data = jsonDecode(response.body);
var listAlbum = data.map<Album>((json) => Album.fromJson(json)).toList();
return listAlbum;
} else {
// If the server did not return a 200 OK response,
// then throw an exception.
throw Exception('Failed to load Album');
}
}
Your json must be like this=> [{
"userId": 1,
"id": 1,
"title": "quidem molestiae enim"
},
{
"userId": 2,
"id": 2,
"title": "quidem molestiae"
}]
Update your Album class like this.
import 'dart:convert';
List<Album> albumFromJson(String str) => List<Album>.from(json.decode(str).map((x) => Album.fromJson(x)));
class Album {
Album({
this.userId,
this.id,
this.title,});
int userId; int id;String title;
factory Album.fromJson(Map<String, dynamic> json) => Album(
userId: json["userId"],
id: json["id"],
title: json["title"],);}
Then,
update your code
Future<Album> fetchAlbum() async {
to
Future<List<Album>> fetchAlbum() async {
and
final Album = Album.fromJson(data[0]);
return Album;
to
final List<Album> AlbumList = albumFromJson(data);
return AlbumList;
Now you can get display multiple data (Data list);

How to solve this List<dynamic> type error in Flutter/Dart

I am very new to flutter and dart. Trying to return a list from this future that pulls data from an api but I keep getting this error. Someone here helped me solve a similar error by casting to a list because I was calling map function on an array that returns an iterable but in this case here I'm not sure what needs to be done.
type List<dynamic> is not a subtype of type FutrueOr<ListCity>>
Data is received like below:
{
"data": {
"127287": {
"Feature_int_id": "127287",
"Admin1_str_code": "US06",
"Country_str_code": "US",
"Feature_str_name": "Acampo",
"Feature_dec_lat": "38.194",
"Feature_dec_lon": "-121.25"
},
"116496": {
"Feature_int_id": "116496",
"Admin1_str_code": "US06",
"Country_str_code": "US",
"Feature_str_name": "Acton",
"Feature_dec_lat": "34.49",
"Feature_dec_lon": "-118.22"
},
"124284": {
"Feature_int_id": "124284",
"Admin1_str_code": "US06",
"Country_str_code": "US",
"Feature_str_name": "Adelanto",
"Feature_dec_lat": "34.665",
"Feature_dec_lon": "-117.512"
},
}
Below is the code for future:
Future<List<City>> fetchCitiesByProvince(provinceCode) async {
final response = await http.get(Uri.https('localhost/msd', 'api/cities/' + provinceCode));
final responseJson = json.decode(response.body);
final dataMap = responseJson['data'];
if (response.statusCode == 200) {
List citiesList = [];
for (var city in dataMap.keys) {
if (dataMap[city]['Admin1_str_code'] == provinceCode) {
citiesList.add(
{
'cityCode': dataMap[city]['Feature_int_id'],
'cityName': dataMap[city]['Feature_str_name']
}
);
}
}
return citiesList;
} else {
throw Exception('Failed to load cities');
}
}
City Class:
class City {
final String cityCode;
final String cityName;
City({#required this.cityCode, #required this.cityName});
factory City.fromJson(Map<String, dynamic> json) {
return City(
cityCode: json['Feature_int_id'],
cityName: json['Feature_str_name']
);
}
}
You need to return List<City> in your method. So, change the following code:
List citiesList = [];
to
List<City> citiesList = [];
--- UPDATE ---
You need to user your City constructor or factory to generate the item from json like this:
City.fromJson(dataMap[city]);
// Or
City(cityCode: dataMap[city]['Feature_int_id'],
cityName: dataMap[city]['Feature_str_name']
);
Here the updated sample code:
Future<List<City>> fetchCitiesByProvince(provinceCode) async {
final response = await http.get(Uri.https('localhost/msd', 'api/cities/' + provinceCode));
final responseJson = json.decode(response.body);
final dataMap = responseJson['data'];
List<City> citiesList = [];
if (response.statusCode == 200) {
for (var city in dataMap.keys) {
if (dataMap[city]['Admin1_str_code'] == provinceCode) {
citiesList.add(City.fromJson(dataMap[city]));
}
}
} else {
throw Exception('Failed to load cities');
// either throwing an error or return empty list.
}
return citiesList;
}

How do you turn a List <dynamic> into a List <Map> >>

I started to learn Flutter because I want to build an app which can handle API-Calls.
But now I'm frustrated because I want to make an infinite Load and don't get it to work.
The Problem is, that the method require an Future<List> but I dont know how to convert the response from the API into an List
Future<List<Map>> _getServerData(int length) async{
String api = data.url +length.toString();
final res=
await http.get("data.url");
if (res.statusCode == 200) {
List<dynamic> resp = jsonDecode(res.body);
return resp;
} else {
throw Exception('Failed to load DATA');
}
}
The whole class is out of an Tutorial from oodavid.
But in his tutorial he dont use an API
Future<List<Map>> _getExampleServerData(int length) {
return Future.delayed(Duration(seconds: 1), () {
return List<Map>.generate(length, (int index) {
return {
"body": WordPair.random().asPascalCase,
"avatar": 'https://api.adorable.io/avatars/60/${WordPair.random().asPascalCase}.png',
};
});
});
}
That was the how he solved it
Down below is the whole class
import 'dart:async';
import 'dart:convert';
import 'package:Kontra/pages/articel_list.dart';
import 'package:http/http.dart' as http;
import 'package:Kontra/api/url.dart' as data;
import 'package:Kontra/api/articelsResponse.dart';
/// Example data as it might be returned by an external service
/// ...this is often a `Map` representing `JSON` or a `FireStore` document
Future<List<Map>> _getServerData(int length) async{
String api = data.url +length.toString();
final res=
await http.get(data.url);
if (res.statusCode == 200) {
List<dynamic> resp = jsonDecode(res.body);
return resp;
} else {
throw Exception('Failed to load DATA');
}
}
/// PostModel has a constructor that can handle the `Map` data
/// ...from the server.
class PostModel {
String sId;
String title;
String text;
String author;
String pictures;
String link;
int postId;
String createdAt;
PostModel({this.title, this.text, this.pictures, this.link, this.postId});
factory PostModel.fromServerMap(Map<String, dynamic> json) {
return PostModel(
title: json['title'],
text: json['text'],
pictures: json['pictures'],
link: json['link'],
postId: json['postId']
);
}
}
/// PostsModel controls a `Stream` of posts and handles
/// ...refreshing data and loading more posts
class PostsModel {
int reload = 0;
Stream<List<PostModel>> stream;
bool hasMore;
bool _isLoading;
List<Map> _data;
StreamController<List<Map>> _controller;
PostsModel() {
_data = List<Map>();
_controller = StreamController<List<Map>>.broadcast();
_isLoading = false;
stream = _controller.stream.map((List<Map> postsData) {
return postsData.map((Map postData) {
return PostModel.fromServerMap(postData);
}).toList();
});
hasMore = true;
refresh();
}
Future<void> refresh() {
return loadMore(clearCachedData: true);
}
Future<void> loadMore({bool clearCachedData = false}) {
if (clearCachedData) {
_data = List<Map>();
hasMore = true;
}
if (_isLoading || !hasMore) {
return Future.value();
}
_isLoading = true;
return _getServerData(reload++).then((postsData) {
_isLoading = false;
_data.addAll(postsData);
hasMore = (_data.length < 30);
_controller.add(_data);
});
}
}
Thanks for your help guys
Try with
return List<Map>.from(resp.whereType<Map>());
Or
return resp.whereType<Map>().toList();
Or
return resp.cast<Map>();