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
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.
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.
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);
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;
}
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>();