Aashi
Aashi

Reputation: 73

RangeError (index): Invalid value: Only valid value is 0: 2 - Flutter

I am trying to fetch a list from API. It shows the error-

RangeError (index): Invalid value: Only valid value is 0: 2

I am practicing fetch api. Can you please tell me what's the issue with my code and how to avoid showing that red screen error in my app?

This is Code-

    RefreshIndicator(
                onRefresh: () {
                  setState(() {});
                  return fetchOpenMenuList(widget.product);
                },
                child: FutureBuilder<MenuListData>(
                  future: futureOpenMenuList,
                  builder: (context, snapshot) {
                    if (snapshot.hasData) {
                      return ListView.builder(
                        padding: EdgeInsets.symmetric(vertical: 8.h),
                        itemCount: snapshot.data!.data.length,
                        itemBuilder: (BuildContext context, int index) {
                          return ListTile(
                            leading: Image.network(
                              snapshot.data!.data[index]!.items[index].thumb.toString()
                              ),
                            title: Text(snapshot.data!.data[index]!.items[index].prodName),
                            subtitle: Text(snapshot.data!.data[index]!.name),
                            trailing: Container(
                                padding: EdgeInsets.all(5.r),
                                decoration: BoxDecoration(
                                  color: Colors.transparent,
                                  borderRadius: BorderRadius.circular(10.r),
                                ),
                                child: Image.asset("assets/images/MenuIcon.png", height: 20.h, width: 20.w)
                            ),
                          );
                        },
                      );

                    } else if (snapshot.hasError) {
                      return Center(child: Text('No Data Found'));
                    }
                    return const Center(
                      child: SizedBox(
                        height: 50.0,
                        width: 50.0,
                        child: CircularProgressIndicator(),
                      ),
                    );
                  },
                ),
              ),

This is my JSON file-

{
    "ignore": 0,
    "code": 1,
    "message": "OK",
    "data": [
        {
            "ctg_id": "1",
            "name": "Fusion",
            "items": [
                {
                    "prod_id": "1",
                    "prod_name": "Italian Sev Puri",
                    "thumb": "http:\/\/www.galacaterers.in\/images\/menu-items\/thumb-1459925145.jpg"
                }
            ]
        },
        {
            "ctg_id": "5",
            "name": "Cake And Pastries",
            "items": [
                {
                    "prod_id": "57",
                    "prod_name": "Molt And Magic",
                    "thumb": "http:\/\/www.galacaterers.in\/images\/menu-items\/thumb-1459945416.jpg"
                },
                {
                    "prod_id": "49",
                    "prod_name": "Chocolate Zuzups",
                    "thumb": "http:\/\/www.galacaterers.in\/images\/menu-items\/thumb-1459945068.jpg"
                }
            ]
        },
        {
            "ctg_id": "6",
            "name": "Chaat",
            "items": [
                {
                    "prod_id": "99",
                    "prod_name": "Makai Roll Chaat",
                    "thumb": "http:\/\/www.galacaterers.in\/images\/menu-items\/thumb-1459966275.jpg"
                }
            ]
        },
        {
            "ctg_id": "46",
            "name": "Sweet Bite",
            "items": [
                {
                    "prod_id": "23",
                    "prod_name": "Fruit Wati",
                    "thumb": "http:\/\/www.galacaterers.in\/images\/menu-items\/thumb-1459942869.jpg"
                }
            ]
        }
    ]
}

The following is the screenshot of the error:

What I want:

This is Data Model-

import 'dart:convert';

MenuListData menuListDataFromJson(String str) => MenuListData.fromJson(json.decode(str));

String menuListDataToJson(MenuListData data) => json.encode(data.toJson());

class MenuListData {
    MenuListData({
        required this.ignore,
        required this.code,
        required this.message,
        required this.data,
    });

    int ignore;
    int code;
    String message;
    List<Datum> data;

    factory MenuListData.fromJson(Map<String, dynamic> json) => MenuListData(
        ignore: json["ignore"],
        code: json["code"],
        message: json["message"],
        data: List<Datum>.from(json["data"].map((x) => Datum.fromJson(x))),
    );

    Map<String, dynamic> toJson() => {
        "ignore": ignore,
        "code": code,
        "message": message,
        "data": List<dynamic>.from(data.map((x) => x.toJson())),
    };
}

class Datum {
    Datum({
        required this.ctgId,
        required this.name,
        required this.items,
    });

    String ctgId;
    String name;
    List<Item> items;

    factory Datum.fromJson(Map<String, dynamic> json) => Datum(
        ctgId: json["ctg_id"],
        name: json["name"],
        items: List<Item>.from(json["items"].map((x) => Item.fromJson(x))),
    );

    Map<String, dynamic> toJson() => {
        "ctg_id": ctgId,
        "name": name,
        "items": List<dynamic>.from(items.map((x) => x.toJson())),
    };
}

class Item {
    Item({
        required this.prodId,
        required this.prodName,
        required this.thumb,
    });

    String prodId;
    String prodName;
    String thumb;

    factory Item.fromJson(Map<String, dynamic> json) => Item(
        prodId: json["prod_id"],
        prodName: json["prod_name"],
        thumb: json["thumb"],
    );

    Map<String, dynamic> toJson() => {
        "prod_id": prodId,
        "prod_name": prodName,
        "thumb": thumb,
    };
}

Upvotes: 0

Views: 317

Answers (1)

Alex Sunder Singh
Alex Sunder Singh

Reputation: 2584

You are using index for iteration of items as well, that is bad. Instead take first element from items.

Your ListTile code should be like..

return ListTile(
  leading: Image.network(
    snapshot.data!.data[index]!.items[0].thumb.toString() //Make sure items is not empty
  ),
  title: Text(snapshot.data!.data[index]!.items[0].prodName),
  subtitle: Text(snapshot.data!.data[index]!.name),
  trailing: Container(
    padding: EdgeInsets.all(5.r),
    decoration: BoxDecoration(
      color: Colors.transparent,
      borderRadius: BorderRadius.circular(10.r),
    ),
    child: Image.asset(
      "assets/images/MenuIcon.png", 
      height: 20.h, 
      width: 20.w,
    ),
  ),
);

Edited

I added temporary fix with Column for iterating items in data.

RefreshIndicator(
  onRefresh: () {
    setState(() {});
    return fetchOpenMenuList(widget.product);
  },
  child: FutureBuilder<MenuListData>(
    future: futureOpenMenuList,
    builder: (context, snapshot) {
      if (snapshot.hasData) {
        return ListView.builder(
          padding: EdgeInsets.symmetric(vertical: 8.h),
          itemCount: snapshot.data!.data.length,
          itemBuilder: (BuildContext context, int index) {
            return Column(
              children: [
                for(final item in snapshot.data!.data[index]!.items)
                ListTile(
                  leading: Image.network(
                    item.thumb.toString()
                   ),
                   title: Text(item.prodName),
                   subtitle: Text(snapshot.data!.data[index]!.name),
                   trailing: Container(
                     padding: EdgeInsets.all(5.r),
                     decoration: BoxDecoration(
                       color: Colors.transparent,
                       borderRadius: BorderRadius.circular(10.r),
                     ),
                     child: Image.asset(
                       "assets/images/MenuIcon.png", 
                       height: 20.h, 
                       width: 20.w,
                     ),
                   ),
                 ),
               ],
             );
           },
         );
       } else if (snapshot.hasError) {
         return Center(child: Text('No Data Found'));
       }
       return const Center(
         child: SizedBox(
           height: 50.0,
           width: 50.0,
           child: CircularProgressIndicator(),
         ),
       );
     },
   ),
 )

Hope this archives your goal.

Upvotes: 1

Related Questions