Reputation: 497
I am trying to fetch data from an API. I got the error 'type List is not a subtype of Map. I am new to this and didn't understand where I am making mistake.
This is my fetch post function:
Future<Post> fetchPost() async {
final response = await http.get('http://starlord.hackerearth.com/beercraft');
if (response.statusCode == 200) {
return Post.fromJson(json.decode(response.body));
} else {
throw Exception('Failed to load post');
}
}
In my home screen I am using a FutureBuilder
like this:
final Future<Post> post;
HomeScreen({Key key, this.post}) : super(key: key);
FutureBuilder<Post>(
future: post,
builder: (context, result) {
if (result.hasData) {
return ListView.builder(
itemBuilder: (context, index){
return cartItemComponent(result.data.name, result.data.abv, result.data.ounces);
},
);
} else if (result.hasError) {
return Text("${result.error}");
}
// By default, show a loading spinner.
return CircularProgressIndicator();
},
How can I resolve this error? Thanks in advance.
Upvotes: 2
Views: 1345
Reputation: 126564
The reason for this is that the API you are calling (http://starlord.hackerearth.com/beercraft
) returns a list of JSON objects, but you are handling it as if there was only a single object.
You will need to rewrite your code to handle it as a list instead, which should work perfectly with your ListView
:
Future<List<Post>> fetchPosts() async {
final response = await http.get('http://starlord.hackerearth.com/beercraft');
if (response.statusCode == 200) {
return json.decode(response.body).map<Post>((item) => Post.fromJson(item)).toList();
} else {
throw Exception('Failed to load post');
}
}
fetchPost
needs to be updated to fetchPosts
to return a Future<List<Post>>
. Here you can simply map every item in the response list to a Post
object using List.map
.
The next step is to handle the returned Future
as a list in your FutureBuilder
like this:
final Future<List<Post>> posts;
FutureBuilder(
future: posts,
builder: (context, AsyncSnapshot<List<Post>> snapshot) {
if (snapshot.hasData) {
return ListView(
children: snapshot.data.map<Widget>((post) {
return cartItemComponent(post.name, post.abv, post.ounces);
}).toList(),
);
} else if (snapshot.hasError) {
return Text('${snapshot.error}');
}
// By default, show a loading spinner.
return const CircularProgressIndicator();
}
)
Notice that I simply passed the list as a list of Widget
's to the children
parameter of ListView
because no builder is needed in this case.
I simply made use of the map
method again to transform the Post
's into Widget
's using your cartItemComponent
function.
Upvotes: 2