Gheh
Gheh

Reputation: 305

How to use a variable value outside a Future function in Flutter?

I want to access the items to use inside the widget to generate a List of items. How should I do it? I am new to flutter. Here is the full code for the widget that will generate the List. This is my problem that I cannot figure out since yesterday. I'm hoping to get enlightened.

class Breakfast extends StatefulWidget {
      Breakfast({
    Key? key,
  }) : super(key: key);


  @override
  _BreakfastState createState() => _BreakfastState();
}

class _BreakfastState extends State<Breakfast> {

  Future<String> _loadloadBreakfastAsset() async {
    return await rootBundle.loadString('assets/breakfast.json');
  }

  Future<List<Breakfast>> loadBreakfast() async{
    String jsonAddress = await _loadloadBreakfastAsset();
    Map<String,dynamic> map = json.decode(jsonAddress);
    List<dynamic> items = map["items"];
    // This return value is thrown away, but this line is necessary to 
    // resolve the Future call that FutureBuilder is waiting on.
    return Future<List<Breakfast>>.value();
  }

  @override
Widget build(BuildContext context) {


      return FutureBuilder(
      future: loadBreakfast(),
      builder: (BuildContext, AsyncSnapshot<dynamic>snapshot){
        return Column(
          children: [
            Padding(
              padding:
                  EdgeInsets.symmetric(horizontal: getProportionateScreenWidth(20)),
              child: SectionTitle(title: "Choices", press: () {}),
            ),
            SizedBox(height: getProportionateScreenWidth(20)),
            SingleChildScrollView(
              scrollDirection: Axis.horizontal,
              child: Row(
                children: [
                  ...List.generate(
                          
                    snapshot.data![index].length,
                    (index) {
                      if (items[index].isPopular) {
                        return BreakfastCard(breakfast: items[index]); 
                      }
                      return const SizedBox
                          .shrink(); // here by default width and height is 0
                    },
                  ),
                  SizedBox(width: getProportionateScreenWidth(20)),
                ],
              ),
            )
          ],
        );
      });
  }
}

Here is the JSON data ....

{
    "items": [{

            "id": 1,
            "rating": "4.7",
            "images": [
                "assets/images/egg.png"
            ],
            "title": "Fried Egg",
            "description": "Sunny",
            "isFavorite": false,
            "isPopular": true,
            "serving": 1

        }, {

            "id": 2,
            "rating": "4.0",
            "images": [
                "assets/images/longanisa.png"
            ],
            "title": "Longanisa",
            "description": "Yum",
            "isFavorite": false,
            "isPopular": false,
            "serving": 3

        }

    ]
}

Upvotes: 0

Views: 1440

Answers (3)

Md. Yeasin Sheikh
Md. Yeasin Sheikh

Reputation: 63569

You are using Future<Breakfast> where it is returning List<Breakfast>.

Change method return type List<Breakfast> items to

Future<List<Breakfast>> loadBreakfast() async{..}.


If you check JSON file, it contains single key items and its value is List<Breakfast>.

Learn more about ackground-parsing

To simplify the JSON process, make a model class that will contain parser.


class Breakfast {
  int id;
  String rating;
  List<String> images;
  String title;
  String description;

  bool isFavorite;
  bool isPopular;
  int serving;

  Breakfast({
    required this.id,
    required this.rating,
    required this.images,
    required this.title,
    required this.description,
    required this.isFavorite,
    required this.isPopular,
    required this.serving,
  });

  Map<String, dynamic> toMap() {
    return {
      'id': id,
      'rating': rating,
      'images': images,
      'title': title,
      'description': description,
      'isFavorite': isFavorite,
      'isPopular': isPopular,
      'serving': serving,
    };
  }

  factory Breakfast.fromMap(Map<String, dynamic> map) {
    return Breakfast(
      id: map['id'],
      rating: map['rating'],
      images: List<String>.from(map['images']),
      title: map['title'],
      description: map['description'],
      isFavorite: map['isFavorite'],
      isPopular: map['isPopular'],
      serving: map['serving'],
    );
  }

  String toJson() => json.encode(toMap());

  factory Breakfast.fromJson(String source) =>
      Breakfast.fromMap(json.decode(source));
}

You can check my short note formatting different types of JSON.

import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';


void main() {
  runApp(
    App(),
  );
}
class App extends StatelessWidget {
  const App({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      debugShowCheckedModeBanner: false,
      home: BreakfastView(),
    );
  }
}

class BreakfastView extends StatefulWidget {
  const BreakfastView({Key? key}) : super(key: key);

  @override
  State<BreakfastView> createState() => _BreakfastViewState();
}

class _BreakfastViewState extends State<BreakfastView> {
  Future<List<Breakfast>> loadBreakfast() async {
    String jsonAddress =
        await rootBundle.loadString('assets/json/breakfast.json');
    final jsonString = json.decode(jsonAddress)['items'] as List;

    final List<Breakfast> items =
        jsonString.map((s) => Breakfast.fromMap(s)).toList();

    return items;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: FutureBuilder<List<Breakfast>>(
          future: loadBreakfast(),
          builder: (context, snapshot) {
            if (snapshot.connectionState == ConnectionState.waiting) {
              return const CircularProgressIndicator();
            } else if (snapshot.hasError) {
              return Text("${snapshot.error}");
            } else if (snapshot.hasData) {
              return ListView.builder(
                itemCount: snapshot.data!.length,
                itemBuilder: (context, index) {
                  return ListTile(
                    title: Text(snapshot.data![0].title),
                  );
                },
              );
            }

            return const Text("handle others");
          }),
    );
  }
}

Breakfast widget and model class are different.

I will suggest you to start from basic. Visit flutter.dev for more about it.

Upvotes: 0

Albert
Albert

Reputation: 91

Try removing the triple dots ...List.generate() so you just remain with List.generate()

Upvotes: 0

Diwyansh
Diwyansh

Reputation: 3514

You'll need a FutureBuilder to get the value and build a list containing data just make some changes to your Future function

Future<List> loadBreakfast() async {
    String jsonAddress = await _loadloadBreakfastAsset();
    Map<String, dynamic> map = json.decode(jsonAddress);
    List<dynamic> items = map["items"]; 
   
    return items;
  }

and use FutureBuilder Now

FutureBuilder(
        future: loadBreakfast(),
        builder: (context, AsyncSnapshot<List> snapshot) => ListView.builder(
            itemCount: snapshot.data!.length,
            itemBuilder: (context, index) => Text("${snapshot.data![index]}")));

Upvotes: 1

Related Questions