Home > other >  type 'Null' is not a subtype of type 'List<dynamic>' in type cast in flutt
type 'Null' is not a subtype of type 'List<dynamic>' in type cast in flutt

Time:11-05

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 :)

  • Related