How to get data from json in flutter

Question

Asked by Gheh on November 12, 2021 (source).

I'm trying to access my JSON data, but it returns me this error. I already manipulated the structure of my JSON but nothing seems to fix. I tried to use [{:[{}]}] or {:[{}]} for JSON format but the error persist. I want to display the data that I can get into a container.

ERROR: RangeError (RangeError (index): Invalid value: Valid value range is empty: 0)

This is my code.

    import 'dart:convert';
    
    import 'package:flutter/material.dart';
    import 'package:flutter/services.dart';
    import 'package:flutter_svg/flutter_svg.dart';
    
    import '../constants (2).dart';
    import '../constants.dart';
    import '../size_config.dart';
    
    class BreakfastCard extends StatefulWidget {
    
        BreakfastCard({
        Key? key,
        this.width = 140,
        this.aspectRetio = 1.02,
      }) : super(key: key);
    
      final double width, aspectRetio;
      @override
      _BreakfastCardState createState() => _BreakfastCardState();
    }
     
    class _BreakfastCardState extends State<BreakfastCard> {
      List breakfast = [];
    
              Future<void> loadBreakfastAsset() async {
              final String loadBreakfastAsset = await rootBundle.loadString('assets/data.json');
              final breakfast = await json.decode(loadBreakfastAsset);
      }
    
    
      @override
      Widget build(BuildContext context) {
        SizeConfig().init(context);
          return Padding(
            padding: EdgeInsets.only(left: getProportionateScreenWidth(20)),
            child: SizedBox(
              width: getProportionateScreenWidth(140),
              child: GestureDetector(
                onTap: (){},
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    AspectRatio(
                      aspectRatio: 1.02,
                      child: Container(
                        padding: EdgeInsets.all(getProportionateScreenWidth(20)),
                        decoration: BoxDecoration(
                          color: kSecondaryColor.withOpacity(0.1),
                          borderRadius: BorderRadius.circular(15),
                        ),
                        child: Hero(
                          tag: breakfast[0]["id"],
                          child: Image.asset(breakfast[0]["images"]),
                        ),
                      ),
                    ),
                    const SizedBox(height: 10),
                    Text(
                      breakfast[0]["title"],
                      style: const TextStyle(color: Colors.black),
                      maxLines: 2,
                    ),
                    Row(
                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
                      children: [
                        Text(
                          "${breakfast[0]["calories"]} cal |",
                          style: TextStyle(
                            fontSize: getProportionateScreenWidth(18),
                            fontWeight: FontWeight.bold,
                            color: kPrimaryColor,
                          ),
                        ),
        
                        Text(
                          "${breakfast[0]["time"]} min",
                          style: TextStyle(
                            fontSize: getProportionateScreenWidth(18),
                            fontWeight: FontWeight.w600,
                            color: kPrimaryColor,
                          ),
                        ),
                        InkWell(
                          borderRadius: BorderRadius.circular(50),
                          onTap: () { breakfast[0]["isFavorite"] = !breakfast[0]["isFavorite"];},
                          child: Container(
                            padding: EdgeInsets.all(getProportionateScreenWidth(8)),
                            height: getProportionateScreenWidth(28),
                            width: getProportionateScreenWidth(28),
                            child: SvgPicture.asset(
                              "assets/icons/Heart Icon_2.svg",
                              color: breakfast[0]["images"]
                                  ? const Color(0xFFFF4848)
                                  : const Color(0xFFDBDEE4),
                            ),
                          ),
                        ),
                      ],
                    )
                  ],
                ),
              ),
            ),
          );
  
      }
    }

Here is my json file :

[{
    "items": [{

        "id": "1",
        "rating": "0.0",
        "images": [
            "assets/images/cilantro.png"
        ],
        "title": "Cilantro and Kale Pesto Toast with a Fried Egg",
        "time": "15",
        "description": "Sliced bread is the perfect blank canvas, ready to be loaded up with virtuous ingredients.",
        " rating": "4.8",
        "isFavorite": "false",
        "isPopular": "true",
        "calories": "405",
        "serving": 1,
        "naturalFacts": [
            "405 calories",
            "protein 15g",
            "fat 31g",
            "saturated fat 5.8g",
            "carbohydrates 16g",
            "fiber 1.9g",
            "sodium 331mg",
            "cholesterol 189mg"

        ],
        "ingredients": [
            "¼ cup packed cilantro",
            "1 cup packed kale leaves",
            "¼ cup extra-virgin olive oil",
            "1 tablespoon white balsamic vinegar",
            "2 tablespoons hulled hemp seeds*",
            "salt",
            "Freshly ground pepper",
            "1 large slice of whole-wheat toast",
            "2 tablespoons unflavored whole-milk Greek yogurt",
            "1 fried egg"
        ],
        "procedure": [
            "Whirl the cilantro, kale leaves, extra-virgin olive oil, white balsamic vinegar, and hemp seeds* until fairly smooth, scraping inside of bowl.",
            "Season with sea salt and freshly ground pepper. Smear a large slice of whole-wheat toast with the yogurt, then with some pesto.",
            "Top with a fried egg and more salt and pepper."
        ]

    }]
}]

Here is the Models

import 'package:flutter/material.dart';

class Breakfast {
  final int id, time, serving;
  final String title, description, calories;
  final List <String> procedure;
  final List <String> ingredients;
  final List <String> naturalFacts;
  final List<String> images;
  final double rating;
  bool isFavorite, isPopular;

  Breakfast({
    required this.id,
    required this.images,
    this.rating = 0.0,
    this.isFavorite = false,
    this.isPopular = false,
    required this.title,
    required this.time,
    required this.description,
    required this.ingredients,
    required this.procedure,
    required this.naturalFacts,
    required this.calories,
    required this.serving,
  });

    factory Breakfast.fromJson(Map<String, dynamic> parsedJson) {
    var procedureFromJson  = parsedJson['procedure'];
    var ingredientsFromJson  = parsedJson['ingredients'];
    var naturalFactsFromJson  = parsedJson['naturalFacts'];
    var imagesFromJson  = parsedJson['images'];
    
    //print(streetsFromJson.runtimeType);
    // List<String> streetsList = new List<String>.from(streetsFromJson);
    List<String> ingredientsList = ingredientsFromJson.cast<String>();
    List<String> procedureList = procedureFromJson.cast<String>();
    List<String> imagesList = imagesFromJson.cast<String>();

    return new Breakfast(
      calories: parsedJson['calories'],
      time: parsedJson['time'],
      title: parsedJson['title'],
      description: parsedJson['description'],
      naturalFacts: parsedJson['naturalFacts'],
      serving: parsedJson['serving'],
      id: parsedJson['id'],

      procedure: procedureList,
      ingredients: ingredientsList,
      images: imagesList,
    );
  }
}

Answer

Question answered by Yeasin S (source).

Firstly, while we don't need [] at outer side of JSON data.

The second issue is coming from data type. On JSON modeling. If you look closely, id is String on JSON but int on model class. Convert id to int on JSON,

Like "id": 1, also same goes for others fields, do a check on datatype and create model based on that.

enter image description here

Thirdly, it requires using FutureBuilder to load asset's JSON and parsing it.

It will be like

  Future<List<Breakfast>> loadBreakfastAsset() async {
    final String _loadBreakfastAsset =
        await rootBundle.loadString('json/bg.json');
    final jsonString = await json.decode(_loadBreakfastAsset)["items"] as List;
    final breakfastList = jsonString.map((e) => Breakfast.fromJson(e)).toList();

    return breakfastList;
  }

You follow my note on it.

I am sharing the tested code-snippet, you need to check and apply to all.


class Breakfast {
  final int id;
  final int time;
  final int serving;
  final String title;

  final List<String> procedure;

  Breakfast({
    required this.id,
    required this.time,
    required this.serving,
    required this.title,
    required this.procedure,
  });

  factory Breakfast.fromJson(Map<String, dynamic> parsedJson) {
    var procedureFromJson = parsedJson['procedure'];

    List<String> procedureList = procedureFromJson.cast<String>();

    return Breakfast(
      title: parsedJson['title'],
      serving: parsedJson['serving'],
      id: parsedJson['id'],
      time: parsedJson['time'],
      procedure: procedureList,
    );
  }
}

class _BreakfastCardState extends State<BreakfastCard> {
  Future<List<Breakfast>> loadBreakfastAsset() async {
    final String _loadBreakfastAsset =
        await rootBundle.loadString('json/bg.json');
    final jsonString = await json.decode(_loadBreakfastAsset)["items"] as List;
    final breakfastList = jsonString.map((e) => Breakfast.fromJson(e)).toList();

    return breakfastList;
  }

  @override
  Widget build(BuildContext context) {
    // SizeConfig().init(context);
    return FutureBuilder<List<Breakfast>>(
        future: loadBreakfastAsset(),
        builder: (context, snapshot) {
          if (snapshot.connectionState == ConnectionState.waiting) {
            return const CircularProgressIndicator();
          } else if (snapshot.hasError) {
            return Text("Got ERR :${snapshot.error}");
          } else if (snapshot.hasData) {
            final List<Breakfast> breakfast = snapshot.data!;
            return Padding(
              padding: const EdgeInsets.only(left: (20)),
              child: SizedBox(
                // width: getProportionateScreenWidth(140),
                width: 100,
                height: 200,
                child: GestureDetector(
                  onTap: () {},
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      AspectRatio(
                        aspectRatio: 1.02,
                        child: Container(
                          // padding: EdgeInsets.all(getProportionateScreenWidth(20)),
                          decoration: BoxDecoration(
                            // color: kSecondaryColor.withOpacity(0.1),
                            borderRadius: BorderRadius.circular(15),
                          ),
                          // child: Hero(
                          //   tag: breakfast[0]["id"],
                          //   child: Image.asset(breakfast[0]["images"]),
                          // ),
                        ),
                      ),
                      const SizedBox(height: 10),
                      Text(
                        breakfast[0].title,
                        style: const TextStyle(color: Colors.black),
                        maxLines: 2,
                      ),
                      Row(
                        mainAxisAlignment: MainAxisAlignment.spaceBetween,
                        children: [
                          // Text(
                          //   "${breakfast[0].calories} cal |",
                          //   style: TextStyle(
                          //     // fontSize: getProportionateScreenWidth(18),
                          //     fontWeight: FontWeight.bold,
                          //     // color: kPrimaryColor,
                          //   ),
                          // ),
                          Text(
                            "${breakfast[0].time} min",
                            style: TextStyle(
                              // fontSize: getProportionateScreenWidth(18),
                              fontWeight: FontWeight.w600,
                              // color: kPrimaryColor,
                            ),
                          ),
                          InkWell(
                            borderRadius: BorderRadius.circular(50),
                            onTap: () {
                              // breakfast[0].isFavorite =
                              //     !breakfast[0].isFavorite;
                            },
                            child: Container(
                                padding: EdgeInsets.all((8)), child: Text("A")),
                          ),
                        ],
                      )
                    ],
                  ),
                ),
              ),
            );
          }
          return Text("...");
        });
  }
}
FLUTTER JSON
SHARE: