Reputation: 3071
I made a random json that has a list of people and things they bought and this is the content:
random.json
{
"people": [
{
"name": "person1",
"id": "1",
"thingsbought": {
"fish": {
"price" : "10"
},
"chicken": {
"price" : "5"
},
"vegetables": {
"price" : "15"
},
"drinks": {
"price" : "10"
}
}
},
{
"name": "person2",
"id": "2",
"thingsbought": {
"fish": {
"price" : "10"
},
"vegetables": {
"price" : "15"
}
}
},
{
"name": "person3",
"id": "3",
"thingsbought": {
"chicken": {
"price" : "5"
},
"vegetables": {
"price" : "15"
},
"drinks": {
"price" : "10"
}
}
}
]
}
The app consists of two pages. The first page displays the list of names with their ID's while the next page lists things they bought based on their index number in the JSON.
I dont have a problem with the first page. This is the screenshot for context purposes.
While this is the next page after clicking on any person
ThingsBought.dart (Second Page)
import 'package:flutter/material.dart';
import 'dart:async' show Future;
import 'dart:convert';
import 'package:http/http.dart' as http;
final String url = "http://crm.emastpa.com.my/random.json";
Future<String> loadThings() async {
var res = await http.get(
Uri.encodeFull(url),
headers: {"Accept": "application/json"});
return res.body;
}
class ThingsBought extends StatefulWidget {
ThingsBought({Key key, this.index, this.name}) : super(key:key);
final int index;
final String name;
@override
_ThingsBoughtState createState() => _ThingsBoughtState();
}
class _ThingsBoughtState extends State<ThingsBought> {
makeCard(String title, String price){
return new Card(
child: new ExpansionTile(
title: new Text(title),
children: <Widget>[
new ListTile(
title: new Text("Price"),
trailing: new Text(price),
)
]),
);
}
@override
Widget build(BuildContext context) {
Widget body = new Container(
child: new FutureBuilder(
future: loadThings(),
builder: (context, snapshot){
if(snapshot.hasData){
List<Widget> widgets = [];
Map decoded = json.decode(snapshot.data)["people"][widget.index]["thingsbought"];
var fishprice = decoded["fish"]["price"];
var chickenprice = decoded["chicken"]["price"];
var vegetableprice = decoded["vegetables"]["price"];
var drinkprice = decoded["drinks"]["price"];
if(decoded.containsKey("fish")){
widgets.add(makeCard("Fish", fishprice));
}else{
return new Container();
}
if(decoded.containsKey("chicken")){
widgets.add(makeCard("Chicken", chickenprice));
}else{
return new Container();
}
if(decoded.containsKey("vegetables")){
widgets.add(makeCard("Vegetables", vegetableprice));
}else{
return new Container();
}
if(decoded.containsKey("drinks")){
widgets.add(makeCard("Drinks", drinkprice));
}else{
return new Container();
}
return new Column(
children: widgets,
);
}else{
return new Center(
child: new CircularProgressIndicator(),
);
}
}
),
);
return new Scaffold(
appBar: new AppBar(
title: new Text("Things Bought"),
),
body: new SingleChildScrollView(
child: body,
),
);
}
}
The issue here is that, whenever I click on the person1
which is the first index, It comes out just fine.
Screenshot for first index that works just fine
But clicking on the other persons results in an error as shown in the screenshot below.
Screenshot for second index and third index which has the error
I know for sure that the first index works because all of the keys exist. But I wonder why the other ones failed to be read even when I put return new Container();
as the else statement.
Could anyone explain to me what I am doing wrong and how do I correct my code?
Upvotes: 1
Views: 8889
Reputation: 3071
For anyone facing this issue, I have found the solution that worked for me.
The problem occurs when the variables needed to call the Keys are declared outside the if statement
THIS IS WRONG
var fishprice = decoded["fish"]["price"];
var chickenprice = decoded["chicken"]["price"];
var vegetableprice = decoded["vegetables"]["price"];
var drinkprice = decoded["drinks"]["price"];
if(decoded.containsKey("fish")){
widgets.add(makeCard("Fish", fishprice));
}else{
return new Container();
}
if(decoded.containsKey("chicken")){
widgets.add(makeCard("Chicken", chickenprice));
}else{
return new Container();
}
if(decoded.containsKey("vegetables")){
widgets.add(makeCard("Vegetables", vegetableprice));
}else{
return new Container();
}
if(decoded.containsKey("drinks")){
widgets.add(makeCard("Drinks", drinkprice));
}else{
return new Container();
}
THIS IS THE CORRECTED VERSION
//Declare the variables inside the if statement and remove the return from new Container()
if(decoded.containsKey("fish")){
var fishprice = decoded["fish"]["price"];
widgets.add(makeCard("Fish", fishprice));
}else{
new Container();
}
if(decoded.containsKey("chicken")){
var chickenprice = decoded["chicken"]["price"];
widgets.add(makeCard("Chicken", chickenprice));
}else{
new Container();
}
if(decoded.containsKey("vegetables")){
var vegetableprice = decoded["vegetables"]["price"];
widgets.add(makeCard("Vegetables", vegetableprice));
}else{
new Container();
}
if(decoded.containsKey("drinks")){
var drinkprice = decoded["drinks"]["price"];
widgets.add(makeCard("Drinks", drinkprice));
}else{
new Container();
}
So the reasoning behind this change is that: declaring the variables outside the if statement will already call from the json and that is why the error occurs. Therefore the correct way to do it is to call if after the if statement confirms the existence of the key.
Upvotes: 1
Reputation: 5924
In your JSON, fish
, chicken
, vegetables
, drinks
are not set.
The following code will not work. decoded["fish"]
could be null.
var fishprice = decoded["fish"]["price"];
var chickenprice = decoded["chicken"]["price"];
var vegetableprice = decoded["vegetables"]["price"];
var drinkprice = decoded["drinks"]["price"];
Upvotes: 1