I am trying to fetch image from an api. For that I am using http package for flutter. I created Model View Controller pattern to arrange the structure of the project. Here is the api link and response:
https://wrestlingworld.co/wp-json/wp/v2/posts/128354
Response =>
[{"id":128640,"date":"2022-11-04T15:09:58","date_gmt":"2022-11-04T09:39:58","guid":{"rendered":"https:\/\/wrestlingworld.co\/?p=128640"},"modified":"2022-11-04T15:10:04","modified_gmt":"2022-11-04T09:40:04","slug":"impact-knockouts-tag-team-championship-match-announced-for-over-drive-2022","status":"publish","type":"post","link":"https:\/\/wrestlingworld.co\/news\/impact-knockouts-tag-team-championship-match-announced-for-over-drive-2022","title":{"rendered":"Impact Knockouts Tag Team Championship Match Announced for Over Drive"},"content":{"rendered":"\n<p>Impact Knockouts Tag Team Championships will be on the line at Over Drive on November 18th. It has <a href=\"https:\/\/impactwrestling.com\/2022\/11\/03\/tasha-steelz-savannah-evans-look-to-topple-the-death-dollz-in-knockouts-world-tag-team-title-showdown-at-over-drive\/\" target=\"_blank\" rel=\"noreferrer noopener nofollow\">been announced<\/a> that Death Dollz (Taya Valkyrie and Jessicka) will be defending their titles against Tasha Steelz and Savannah
Here is my model:
class NewsModel {
int? id;
String? date;
String? slug;
String? status;
Title? title;
Title? content;
List<OgImage>? ogImage;
int? author;
NewsModel(
{this.id,
this.date,
this.slug,
this.status,
this.title,
this.content,
this.ogImage,
this.author});
NewsModel.fromJson(Map<String, dynamic> json) {
id = json['id'];
date = json['date'];
slug = json['slug'];
status = json['status'];
title = json['title'] != null ? new Title.fromJson(json['title']) : null;
content =
json['content'] != null ? new Title.fromJson(json['content']) : null;
if (json['og_image'] != null) {
ogImage = <OgImage>[];
json['og_image'].forEach((v) {
ogImage!.add(new OgImage.fromJson(v));
});
}
author = json['author'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = this.id;
data['date'] = this.date;
data['slug'] = this.slug;
data['status'] = this.status;
if (this.title != null) {
data['title'] = this.title!.toJson();
}
if (this.content != null) {
data['content'] = this.content!.toJson();
}
if (this.ogImage != null) {
data['og_image'] = this.ogImage!.map((v) => v.toJson()).toList();
}
data['author'] = this.author;
return data;
}
}
class Title {
String? rendered;
Title({this.rendered});
Title.fromJson(Map<String, dynamic> json) {
rendered = json['rendered'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['rendered'] = this.rendered;
return data;
}
}
class OgImage {
String? url;
OgImage({this.url});
OgImage.fromJson(Map<String, dynamic> json) {
url = json['url'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['url'] = this.url;
return data;
}
}
Here you can see OgImage is a list So I created a card and tried this code:
final int id;
final String title;
final String description;
final List<dynamic> img;
const NewsCard({
required this.id,
required this.title,
required this.description,
required this.img,
});
ListView.builder(
itemCount: img.length,
itemBuilder: (context, item){
return Image.network(
img[item],
height: 120,
width: double.infinity
);
},
),
Here is the front end code where I am passing value :
Padding(
padding: const EdgeInsets.all(8.0),
child: ListView.builder(
physics: const ClampingScrollPhysics(),
shrinkWrap: true,
itemCount: allNews.length,
itemBuilder: (context, i) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: NewsCard(
id: allNews[i].id as int,
title: allNews[i].title!.rendered!,
description: allNews[i].content!.rendered!,
img: allNews[i].ogImage?[0].url as List<dynamic>,
),
);
}),),
Here is my controller :
Future<bool> getNews() async {
var url = Uri.parse(urlnews);
// var token = storage.getItem('token');
try {
http.Response response = await http.get(url);
print(response.body);
var data = json.decode(response.body) as List;
// print(data);
List<NewsModel> temp = [];
data.forEach((element) {
NewsModel product = NewsModel.fromJson(element);
temp.add(product);
});
_news = temp;
notifyListeners();
return true;
} catch (e) {
print(e);
return false;
}
}
List<NewsModel> get allNews {
return [..._news];
}
This code has errors I mentioned in the title already. Here I have a qustion like how can I pass list value inside the card. What is right way to fetch lists of image inside a widget.
CodePudding user response:
There are a few issues with your code:
1. In your NewsModel class file, you're mapping it all wrong.
You're mapping json['og_image']
to a List, while json['og_image']
doesn't exist in the first place. If you see the JSON response, instead it's within the json['yoast_head_json']
key. So, instead of json['og_image']
you need to do json['yoast_head_json']['og_image']
.
Change:
if (json['og_image'] != null) {
ogImage = <OgImage>[];
json['og_image'].forEach((v) {
ogImage!.add(new OgImage.fromJson(v));
});
}
to:
if (json['yoast_head_json'] != null &&
json['yoast_head_json']['og_image'] != null) {
ogImage = <OgImage>[];
json['yoast_head_json']['og_image'].forEach((v) {
ogImage!.add(OgImage.fromJson(v));
});
2. In your frontend part, you're trying to cast a nullable type of list allNews[i].ogImage?[0].url as List<dynamic>
to List<dynamic>
, which will throw exception in case the list is NULL
which is in your case.
so, instead of:
img: allNews[i].ogImage?[0].url as List<dynamic>
do:
img: allNews[i].ogImage ?? []
3. Finally, in your NewsCard class:
Change:
Image.network(
img[item],
...
);
to
Image.network(
img[item].url,
...
);
Enjoy :)