i'm new to flutter, i'm trying to display response from the server on my screen. I'm trying to fetchi data from server APIs, The data is being successfully fetched from the server but the issue is that the data it cant be shown.
i have no experience with showing API's data and request to server thing, so i dont know how to display it.
This is my model
class Food {
late int id;
late String title;
late String img_id;
late int user_id;
late int views;
late String bahan;
late String create;
late String update;
late String user;
Food(
{required this.id,
required this.title,
required this.img_id,
required this.user_id,
required this.views,
required this.bahan,
required this.create,
required this.update,
required this.user});
factory Food.fromJson(Map<String, dynamic> json) {
return Food(
id: json['id'],
title: json['title'],
img_id: json['img_id'],
user_id: json['user_id'],
views: json['views'],
bahan: json['bahan'],
create: json['create'],
update: json['update'],
user: json['user']);
}
}
This is my class for calling api
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:project/model/food.dart';
class FoodProvider extends ChangeNotifier {
Future<Food> getFood() async {
var result = await http.get(
Uri.parse('http://sweetreats.herokuapp.com/api/recipe'),
);
print(result.statusCode);
if (result.statusCode == 200) {
// List data = json.decode(result.body);
// List<Food> foods = data.map((item) => Food.fromJson(item)) as List<Food>;
// return foods;
return Food.fromJson(jsonDecode(result.body));
} else {
throw Exception();
}
}
}
and this is the way how i tried to display the data
FutureBuilder<Food>(
future: foodProvider.getFood(),
builder: (context, snapshot) {
if (snapshot.hasData) {
List? data = snapshot.data as List?;
int index = 0;
return Column(
children: data!.map((item) {
index++;
return Container(
margin: EdgeInsets.only(
top: index == 1 ? 0 : 30,
),
child: FoodItem(food: item),
);
}).toList());
}
return Center(
child: CircularProgressIndicator(),
);
}),
Changes in Model
class Food {
final int? id;
final String? title;
final String? img_id;
final int? user_id;
final String? views;
final String? bahan;
final String? create;
final String? update;
final String? user;
Food({
required this.id,
required this.title,
required this.img_id,
required this.user_id,
required this.views,
required this.bahan,
required this.create,
required this.update,
required this.user,
});
factory Food.fromJson(Map<String, dynamic> json) {
return Food(
id: json['id'],
title: json['title'],
img_id: json['img_id'],
user_id: json['user_id'],
views: json['views'],
bahan: json['bahan'],
create: json['create'],
update: json['update'],
user: json['user'],
);
}
}
Changes in Provider
class FoodProvider extends ChangeNotifier {
Future<List<Food>> getFood() async {
try {
var result = await http.get(
Uri.parse('http://sweetreats.herokuapp.com/api/recipe'),
);
if (result.statusCode != 200) {
throw result.body;
}
final data = json.decode(result.body);
return List<Food>.from(
data['recipes'].map((e) => Food.fromJson(e)).toList(),
);
} catch (_) {
rethrow;
}
}
}
Changes in UI
FutureBuilder<List<Food>>(
future: FoodProvider().getFood(),
builder: (context, AsyncSnapshot<List<Food>> snapshot) {
if (snapshot.hasError) {
return Center(
child: Text('Something went wrong ${snapshot.error}'),
);
} else if (snapshot.hasData) {
// return ListView.builder(itemBuilder: (_, i) {}, itemCount: snapshot.data.,)
List? data = snapshot.data;
int index = 0;
return Column(
children: data!.map((item) {
index++;
return Container(
margin: EdgeInsets.only(top: index == 1 ? 0 : 30),
child: Text(item.title ?? ''),
);
}).toList());
} else {
return const Center(child: CircularProgressIndicator());
}
},
),
Related
I'm trying to pull data using github repo tree json with dart (flutter). Expected a value of type 'int', but got one of type 'Null'.
Expanded(
child: SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Container(
..
child: getFileList(),
),
),
),
Expanded in scaffold. I'm not sure I'm using snapshot.data.tree correctly. I want to get all file information.
FutureBuilder getFileList() {
return FutureBuilder<RepoTree>(
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasData) {
return Center(
child: Text(
"File List\n" + snapshot.data.tree,
));
} else if (snapshot.hasError) {
return Center(
child: Text("Error in getFileList " + snapshot.error.toString()));
} else {
return const Center(
child: CircularProgressIndicator(),
);
}
},
future: getResForRepoList(),
);
}
Future<RepoTree> getResForRepoList() async {
final response = await http.get(Uri.parse(
'https://api.github.com/repos/satyasashi/todo_basic/git/trees/master?recursive=1'));
if (response.statusCode == 200) {
return RepoTree.fromJson(
json.decode(response.body));
} else {
throw Exception('Exception in getResForRepoList');
}
}
My classes
class RepoTree {
String sha;
String url;
List<RepoInside> tree;
bool truncated;
RepoTree({
required this.sha,
required this.url,
required this.tree,
required this.truncated,
});
factory RepoTree.fromJson(Map<String, dynamic> json) {
return RepoTree(
sha: json["sha"],
url: json["url"],
// tree: List<RepoInside>.from(
// json["tree"].map((x) => RepoInside.fromJson(x))),
tree: (json['tree'] ?? [])
.map((x) => RepoInside.fromJson(x))
.toList()
.cast<RepoInside>(),
truncated: json["truncated"],
);
}
Map<String, dynamic> toJson() => {
"sha": sha,
"url": url,
"tree": List<String>.from(tree.map((x) => x.toJson())),
"truncated": truncated,
};
}
class RepoInside {
String path;
String mode;
Type type;
String sha;
int size;
String url;
RepoInside({
required this.path,
required this.mode,
required this.type,
required this.sha,
required this.size,
required this.url,
});
factory RepoInside.fromJson(Map<String, dynamic> json) {
return RepoInside(
path: json["path"],
mode: json["mode"],
type: typeValues.map[json["type"]]!,
sha: json["sha"],
size: json["size"] as int,
url: json["url"],
);
}
Map<String, dynamic> toJson() => {
"path": path,
"mode": mode,
"type": typeValues.reverse[type],
"sha": sha,
"size": size,
"url": url,
};
}
enum Type { blob, tree }
final typeValues = EnumValues({"blob": Type.blob, "tree": Type.tree});
class EnumValues<T> {
Map<String, T> map;
Map<T, String> reverseMap = {};
EnumValues(this.map);
Map<T, String> get reverse {
if (reverseMap == null) {
reverseMap = map.map((k, v) => new MapEntry(v, k));
}
return reverseMap;
}
}
I'm having a really hard time on this subject, I would appreciate it if you could explain your answers in detail. Thanks :)
In case if size attribute is null here
factory RepoInside.fromJson(Map<String, dynamic> json) {
return RepoInside(
path: json["path"],
mode: json["mode"],
type: typeValues.map[json["type"]]!,
sha: json["sha"],
size: json["size"] as int,
url: json["url"],
);
}
You can use null-aware oparator ?? to avoid null to get stored in the size field;
You can do it like this
factory RepoInside.fromJson(Map<String, dynamic> json) {
return RepoInside(
path: json["path"],
mode: json["mode"],
type: typeValues.map[json["type"]]!,
sha: json["sha"],
size: json["size"] ?? 0,
url: json["url"],
);
}
What ?? does?
Taking examples
Example 1
int i;
i = null ?? 7;
print(i); //prints 7
Example 2
int i;
i = 10 ?? 7;
print(i); //prints 10
?? will assign the value at left if it is not null, otherwise the right one.
NOTE: make sure that json["size"] is int! If not then you can use var size; instead of int size;.
Future<List<RepoInside>> fetchRepoInsideTree() async {
final response = await http.get(Uri.parse(_link));
if (response.statusCode == 200) {
List jsonResponse = json.decode(response.body)['tree']; // ADD
return jsonResponse.map((e) => RepoInside.fromJson(e)).toList();
} else {
throw Exception('Failed to load RepoInside from API');
}
}
And can be used as in FutureBuilder<List<RepoInside>>()
snapshot.data![i].path()
In short, by adding the ['tree'] expression here, we got the list from the json.
I am working on Getting the values from api through future and converted it into DropDownList. But I am having the issue on showing the values in Drop Down as the user select the value in the Drop Down.Here is my code.
=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>=>
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
class JsonApiDropdown extends StatefulWidget {
#override
JsonApiDropdownState createState() {
return new JsonApiDropdownState();
}
}
class JsonApiDropdownState extends State<JsonApiDropdown> {
Users _currentUser;
final String uri = 'https://jsonplaceholder.typicode.com/users';
Future<List<Users>> _fetchUsers() async {
var response = await http.get(uri);
if (response.statusCode == 200) {
final items = json.decode(response.body).cast<Map<String, dynamic>>();
List<Users> listOfUsers = items.map<Users>((json) {
return Users.fromJson(json);
}).toList();
return listOfUsers;
} else {
throw Exception('Failed to load internet');
}
}
#override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
FutureBuilder<List<Users>>(
future: _fetchUsers(),
builder:
(BuildContext context, AsyncSnapshot<List<Users>> snapshot) {
if (!snapshot.hasData) return CircularProgressIndicator();
return DropdownButton<Users>(
items: snapshot.data
.map((user) => DropdownMenuItem<Users>(
child: Text(user.name),
value: user,
))
.toList(),
onChanged: (Users value) {
setState(() {
_currentUser = value;
});
},
isExpanded: false,
//value: _currentUser,
hint: Text('Select User'),
);
}),
SizedBox(height: 20.0),
_currentUser != null
? Text("Name: " +
_currentUser.name +
"\n Email: " +
_currentUser.email +
"\n Username: " +
_currentUser.username)
: Text("No User selected"),
],
),
);
}
}
class Users {
int id;
String name;
String username;
String email;
Users({
this.id,
this.name,
this.username,
this.email,
});
factory Users.fromJson(Map<String, dynamic> json) {
return Users(
id: json['id'],
name: json['name'],
email: json['email'],
username: json['username'],
);
}
}
You need to add
value =_currentUser;
after your onChanged method on yourdropdownButton
i try to fetch api json id , username , photo ..etc...
and when use jsonplaceholder it's working fine
and when use mine don't get any data
flutter code
import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
class ListViewJsonapi extends StatefulWidget {
_ListViewJsonapiState createState() => _ListViewJsonapiState();
}
class _ListViewJsonapiState extends State<ListViewJsonapi> {
final String uri = 'https://www.christian-dogma.com/android-index.php';
Future<List<Users>> _fetchUsers() async {
var response = await http.get(uri);
if (response.statusCode == 200) {
final items = json
.decode(utf8.decode(response.bodyBytes))
.cast<Map<String, dynamic>>();
List<Users> listOfUsers = items.map<Users>((json) {
return Users.fromJson(json);
}).toList();
return listOfUsers;
} else {
throw Exception('Failed to load internet');
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: FutureBuilder<List<Users>>(
future: _fetchUsers(),
builder: (context, snapshot) {
if (!snapshot.hasData)
return Center(child: CircularProgressIndicator());
return ListView(
children: snapshot.data
.map((user) => ListTile(
title: Text(user.name),
subtitle: Text(user.email),
leading: CircleAvatar(
backgroundColor: Colors.red,
child: Text(user.name[0],
style: TextStyle(
fontSize: 18.0,
color: Colors.white,
)),
),
))
.toList(),
);
},
),
);
}
}
class Users {
int id;
String name;
String username;
String email;
Users({
this.id,
this.name,
this.username,
this.email,
});
factory Users.fromJson(Map<String, dynamic> json) {
return Users(
id: json['id'],
name: json['name'],
email: json['email'],
username: json['username'],
);
}
}
when use https://jsonplaceholder.typicode.com/users it's working fine
and when use mine https://www.christian-dogma.com/android-index.php i don't get any data
He managed to make it work, one of the problems he has is that the id asks me to be a String since you had it as an integer, I hope it worked for you.
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
class JsonApiPhp extends StatefulWidget {
#override
_JsonApiPhpState createState() => _JsonApiPhpState();
}
class _JsonApiPhpState extends State<JsonApiPhp> {
bool loading = true;
final String url = 'https://www.christian-dogma.com/android-index.php';
var client = http.Client();
List<User> users = List<User>();
#override
void initState(){
fetchData();
super.initState();
}
Future<void> fetchData() async {
http.Response response = await client.get(url);
if(response.statusCode == 200){ // Connection Ok
List responseJson = json.decode(response.body);
responseJson.map((m) => users.add(new User.fromJson(m))).toList();
setState(() {
loading = false;
});
} else {
throw('error');
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Container(
child: loading ?
Container(
child: Center(
child: CircularProgressIndicator(),
),
) :
ListView.builder(
itemCount: users.length,
itemBuilder: (BuildContext context, int index){
return Card(
child: ListTile(
title: Text(users[index].username),
),
);
},
)
),
);
}
}
class User {
final String id;
final String name;
final String username;
final String email;
User({
this.id,
this.name,
this.username,
this.email,
});
factory User.fromJson(Map<String, dynamic> json) {
return User(
id: json['id'],
name: json['name'],
email: json['email'],
username: json['username'],
);
}
}
I kind of banged my head around and finally found out that your JSON response is returning the id as a string and not as an integer.
Change the factory to following code.
factory Users.fromJson(Map<String, dynamic> json) {
return Users(
id: int.parse(json['id']),
name: json['name'],
email: json['email'],
username: json['username'],
);
Cheers!
Good I have the following problem I have a json the following http:// and I have the class to get the data for which use https://app.quicktype.io/ and the code is as follows
// To parse this JSON data, do
//
// final moviesFirstLoad = moviesFirstLoadFromJson(jsonString);
import 'dart:convert';
MoviesFirstLoad moviesFirstLoadFromJson(String str) {
final jsonData = json.decode(str);
return MoviesFirstLoad.fromJson(jsonData);
}
String moviesFirstLoadToJson(MoviesFirstLoad data) {
final dyn = data.toJson();
return json.encode(dyn);
}
class MoviesFirstLoad {
List<Movierecent> movierecent;
MoviesFirstLoad({
this.movierecent,
});
factory MoviesFirstLoad.fromJson(Map<String, dynamic> json) => new MoviesFirstLoad(
movierecent: new List<Movierecent>.from(json["movierecent"].map((x) => Movierecent.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"movierecent": new List<dynamic>.from(movierecent.map((x) => x.toJson())),
};
}
class Movierecent {
int id;
String movieId;
String title;
String genre;
String myear;
String released;
String runtime;
String rated;
String director;
String actors;
String plot;
String imdbrating;
String type;
String production;
int internalid;
String poster;
Movierecent({
this.id,
this.movieId,
this.title,
this.genre,
this.myear,
this.released,
this.runtime,
this.rated,
this.director,
this.actors,
this.plot,
this.imdbrating,
this.type,
this.production,
this.internalid,
this.poster,
});
factory Movierecent.fromJson(Map<String, dynamic> json) => new Movierecent(
id: json["id"],
movieId: json["movieID"],
title: json["title"],
genre: json["genre"],
myear: json["myear"],
released: json["released"],
runtime: json["runtime"],
rated: json["rated"],
director: json["director"],
actors: json["actors"],
plot: json["plot"],
imdbrating: json["imdbrating"],
type: json["type"],
production: json["production"],
internalid: json["internalid"],
poster: json["poster"],
);
Map<String, dynamic> toJson() => {
"id": id,
"movieID": movieId,
"title": title,
"genre": genre,
"myear": myear,
"released": released,
"runtime": runtime,
"rated": rated,
"director": director,
"actors": actors,
"plot": plot,
"imdbrating": imdbrating,
"type": type,
"production": production,
"internalid": internalid,
"poster": poster,
};
}
Now the first label shows me that I should use
final moviesFirstLoad = moviesFirstLoadFromJson(jsonString);
therefore I have the following and here I do not know what to do as accessing the data to place them in a list would be something like
Future<List<Movierecent>> loadMovies() async {
final response = await http.get("http://emovies.evolucionone.com/");
if (response.statusCode == 200){
final moviesFirstLoad = moviesFirstLoadFromJson(response.body);
return moviesFirstLoad.movierecent;
}else{
throw Exception ('Failed to load Data');
}
}
I need help to get the data of the json if someone helps me I have already read several topics but none of them works for me ...
Well I answer my questions myself
This to get the data from json
Future<MoviesFirstLoad> loadMovies() async {
final Response response = await http.get(dogApiUrl);
//final List<Movierecent> posterimage = List<Movierecent>();
if (response.statusCode == 200){
//final responsejson = json.decode(response.body);
final moviesFirstLoad = moviesFirstLoadFromJson(response.body);
// moviesFirstLoad.movierecent.forEach((poster) => posterimage.add(poster));
print(moviesFirstLoad);
return moviesFirstLoad;
}else{
throw Exception ('Failed to load Data');
}
}
to show the data in a list
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Movies')),
body: FutureBuilder(
future: loadMovies(),
builder: (BuildContext context, AsyncSnapshot<AppData> snapshot) {
if (!snapshot.hasData) {
return Center(
child: CircularProgressIndicator(),
);
}
return ListView.builder(
itemCount: snapshot.data.movierecent.length,
itemBuilder: (BuildContext context, int index) {
final Movierecent movie = snapshot.data.movierecent[index];
return ListTile(
title: Text(movie.title),
subtitle: Text(movie.genre),
);
},
);
},
),
);
}
}
loadMovies() returns Future<List<Movierecent>> which is a future. If you want underlying list of movies, you could do someting like
loadMovies().then((List<Movierecent> movieList) {
/* do what you want to do here like invoking setState()....*/
}.catchError((e) {
/* Handle Error scenario here */
};
You might want to refer Dart documentation of Futures
I am new to flutter and I tried fetching data from API but I got the error
type'_InternalLinkedHashMap<String, dynamic>' is not a subtype of type 'Iterable<dynamic>'.
I am fetching news data from the API. I tried this for simple API and it worked and when I tried it for a complex API with some changes in the dart code I got this error.
Sorry if I didn't explain correctly. I have pasted all the code that has been used for this API.
I am not getting any solution. I am posting my code here.
post.dart
class Post {
List<Articles> articles;
Post({this.articles});
factory Post.fromJson(Map<String, dynamic> json) {
return Post(
articles: json['articles'].map((value) => new Articles.fromJson(value)).toList(),
);
}
}
article.dart
class Articles{
final String title;
final String description;
final String url;
final String urlToImage;
final String publishedAt;
final String content;
Articles({this.title, this.description, this.url, this.urlToImage, this.publishedAt, this.content});
factory Articles.fromJson(Map<String, dynamic> json) {
return Articles(
title: json['title'],
description: json['description'],
url: json['url'],
urlToImage: json['urlToImage'],
publishedAt: json['publishedAt'],
content: json['content'],
);
}
}
technology_post.dart
Future<List<Post>> fetchPost() async {
final response = await http.get('https://newsapi.org/v2/top-headlines?sources=techcrunch&apiKey=47ada2986be0434699996aaf4902169b');
if (response.statusCode == 200) {
var responseData = json.decode(response.body);
List<Post> posts = [];
for(var item in responseData){
Post news = Post.fromJson(item);
posts.add(news);
}
return posts;
} else {
throw Exception('Failed to load post');
}
}
class Technology extends StatelessWidget{
final Future<List<Post>> post;
Technology({Key key, this.post}) : super (key : key);
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: FutureBuilder<List<Post>>(
future: post,
builder: (context, snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemBuilder: (BuildContext context, int index){
var dataStored = "";
for(var i = 0; i < 10; i++){
dataStored = snapshot.data.articles[i].title;
return ListTile(
title: Text(dataStored),
);
}
}
);
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
}
return CircularProgressIndicator();
},
),
),
);
}
}
homescreen.dart
TabBarView(
children: [
Technology(post: fetchPost()),
Text('General'),
Text('Cricket')
]
I have posted all the required code I hope. If you want to see the API you can see that here
Sorry if I have pasted much code here.
Why am I getting this error and how can I resolve this.
Thanks in advance.
According to your json, there is no List but only Post as json is json object.
So change your fetchPost() function as follows:
Future<Post> fetchPost() async {
final response = await http.get(
'https://newsapi.org/v2/top-headlines?
sources=techcrunch&apiKey=$YOUR_API_KEY');
if (response.statusCode == 200) {
var responseData = jsonDecode(response.body);
var post = Post.fromJson(responseData);
return post;
} else {
throw Exception('Failed to load post');
}
}
NOTE : Remove your api key from your question and paste json only for privacy.
And change your technology class to
class Technology extends StatelessWidget {
final Future<Post> post;
Technology({Key key, this.post}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: FutureBuilder<Post>(
future: post,
builder: (context, snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemBuilder: (BuildContext context, int index) {
return Text(snapshot.data.articles[0].publishedAt);
});
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
}
return CircularProgressIndicator();
},
),
),
);
}
}
and your main problem is also that you have not cast json['articles'] to list. you should change Post.fromJson function to
factory Post.fromJson(Map<String, dynamic> json) {
return Post(
articles: (json['articles'] as List).map((value) => new Articles.fromJson(value)).toList(),
);
}
This should solve your problem.
You should check correct response type Int with String. I see your API status: "ok" and sure you check correctly.