Home > front end >  how to get the json data in a json file locally in flutter
how to get the json data in a json file locally in flutter

Time:11-12

I am trying to get the data from a json file. But I can't done it right. I don't know what is wrong with this. Hope to get an advice or tutorial.

The error I get is : Undefined name 'breakfast'. Then when I change breakfast to Breakfast, I got the error : Instance member '...' can't be accessed using static access. Nothing else. I hope to get an explanation. I'm just a newbie to flutter. I tried to look for the problem and explanation to the web but nothing fix it.

Here is the code:

```import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:models/Breakfast.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 {

  const BreakfastCard({
    Key? key,
    this.width = 140,
    this.aspectRetio = 1.02,
    required this.breakfast,
  }) : super(key: key);

  final double`enter code here` width, aspectRetio;
  final Breakfast breakfast;

  @override
  _BreakfastCardState createState() => _BreakfastCardState();
}
 
class _BreakfastCardState extends State<BreakfastCard> {
  @override
  Widget build(BuildContext context) {
    SizeConfig().init(context);
    return FutureBuilder(
      future: loadBreakfast(),
      builder: (BuildContext, AsyncSnapshot<dynamic>snapshot){
      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.id.toString(),
                      child: Image.asset(breakfast.images[0]),
                    ),
                  ),
                ),
                const SizedBox(height: 10),
                Text(
                  breakfast.title,
                  style: const TextStyle(color: Colors.black),
                  maxLines: 2,
                ),
                Row(
                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
                  children: [
                    Text(
                      "${breakfast.calories} cal |",
                      style: TextStyle(
                        fontSize: getProportionateScreenWidth(18),
                        fontWeight: FontWeight.bold,
                        color: kPrimaryColor,
                      ),
                    ),
    
                    Text(
                      "${breakfast.time} min",
                      style: TextStyle(
                        fontSize: getProportionateScreenWidth(18),
                        fontWeight: FontWeight.w600,
                        color: kPrimaryColor,
                      ),
                    ),
                    InkWell(
                      borderRadius: BorderRadius.circular(50),
                      onTap: () { breakfast.isFavorite = !breakfast.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.isFavorite
                              ? const Color(0xFFFF4848)
                              : const Color(0xFFDBDEE4),
                        ),
                      ),
                    ),
                  ],
                )
              ],
            ),
          ),
        ),
      );
    }
    );
    
  }
    Future<String> _loadloadBreakfastAsset() async {
    return await rootBundle.loadString('assets/data.json');
  }

  Future loadBreakfast() async {
    String jsonAddress = await _loadloadBreakfastAsset();
    final jsonResponse = json.decode(jsonAddress);
    Breakfast breakfast = Breakfast.fromJson(jsonResponse);

    
  }

}```

This is the Model


    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'];
        
        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,
        );
      }
    }

The json data


    [
        {
        "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."
            ]
        }
    ]

CodePudding user response:

From just my visual inspection of your code, I would say start by fixing up your loadBreakfast() method.

Your original code...

Future loadBreakfast() async {
  String jsonAddress = await _loadloadBreakfastAsset();
  final jsonResponse = json.decode(jsonAddress);
  Breakfast breakfast = Breakfast.fromJson(jsonResponse);
}

A Future is Dart's name for a Promise()

It's better if the method returns a type of future. Your method doesn't return anything at all. When your FutureBuilder calls loadBreakfast, it's probably receiving a null response and no work is getting done.

This change fixes the Future's return issue:

Future<Breakfast> loadBreakfast() async {
  String jsonAddress = await _loadloadBreakfastAsset();
  final jsonResponse = json.decode(jsonAddress);
  // This line is a problem. See my later comments.
  // Breakfast breakfast = Breakfast.fromJson(jsonResponse);
  return Future<Breakfast>.value(Breakfast.fromJson(jsonResponse));
}

This line is not doing what you think it is.

Breakfast breakfast = Breakfast.fromJson(jsonResponse);

This declares a new variable named 'breakfast', assigns the value of the parsed JSON to it, then the method finishes and throws the variable away.

BTW, this is an example of code that relies on side effects, and you should rethink how you do this.

Nothing changes the value you declared at the beginning of the method. Here is how to get the effect you want.

I'm going to assume that you want to assign the parsed JSON return to the 'breakfast' property you defined in the top of the widget. If so, this is how you should do it.

First, move the two methods at the bottom of the file into the scope of the _BreakfastCardState class.

  }<--- move this brace past the end of loadBreakfast()
    Future<String> _loadloadBreakfastAsset() async {
    return await rootBundle.loadString('assets/data.json');
  }

  Future loadBreakfast() async {
    String jsonAddress = await _loadloadBreakfastAsset();
    final jsonResponse = json.decode(jsonAddress);
    Breakfast breakfast = Breakfast.fromJson(jsonResponse);

    
  }

This will allow these methods to access the breakfast variable in the StatefulWiget's scope.

Now you would like to change loadBreakfast() into this form.

Future<Breakfast> loadBreakfast() async {
  String jsonAddress = await _loadloadBreakfastAsset();
  final jsonResponse = json.decode(jsonAddress);

  // This now updates the breakfast property in the main class.
  widget.breakfast = Breakfast.fromJson(jsonResponse);

  // This return value is thrown away, but this line is necessary to 
  // resolve the Future call that FutureBuilder is waiting on.
  return Future<Breakfast>.value(null);
}

The final effect should be that the FutureBuilder waits until you parse your JSON file and update 'breakfast' with its parsed value, then you resolve the Future.

FutureBuilder then calls your predicate code, and the return should have all the values you expect.

ONE MORE THING: Everywhere in your Widget code that you have 'breakfast.', change that to 'widget.breakfast.'

If this works out for you, please mark this as the accepted answer.

  • Related