Reputation: 305
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
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
Reputation: 91
Try removing the triple dots ...List.generate()
so you just remain with List.generate()
Upvotes: 0
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