问题
It contains lots of list and nested objects. I need to display all the DishName from the json file
Json URL adress : Json address!! Check this out
i wanted to display the DishName in to my app in which there are lots of dishname in the json list. i parsed the json file using instantly parse json website. But now i dont know how to implent it on my app
code i wrote :
body: Container(
child: Center(
child: FutureBuilder(
future:
DefaultAssetBundle.of(context).loadString('jsons/data.json'),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return CircularProgressIndicator();
}
var myData = jsonDecode(snapshot.data);
final welcome = welcomeFromJson(myData);
print(myData.length);
return ListView.builder(
itemBuilder: (BuildContext context, int index) {
return Card(
child: ListTile(
title: Text(welcome[index]
.tableMenuList[index]
.categoryDishes[index]
.dishName),
));
},
itemCount: myData == null ? 0 : myData.length,
);
},
),
),
),
i am getting error : type 'List' is not a subtype of type 'String'
this is the json class:-
// To parse this JSON data, do
//
// final welcome = welcomeFromJson(jsonString);
import 'dart:convert';
List<Welcome> welcomeFromJson(String str) =>
List<Welcome>.from(json.decode(str).map((x) => Welcome.fromJson(x)));
String welcomeToJson(List<Welcome> data) =>
json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
class Welcome {
String restaurantId;
String restaurantName;
String restaurantImage;
String tableId;
String tableName;
String branchName;
String nexturl;
List<TableMenuList> tableMenuList;
Welcome({
this.restaurantId,
this.restaurantName,
this.restaurantImage,
this.tableId,
this.tableName,
this.branchName,
this.nexturl,
this.tableMenuList,
});
factory Welcome.fromJson(Map<String, dynamic> json) => Welcome(
restaurantId: json["restaurant_id"],
restaurantName: json["restaurant_name"],
restaurantImage: json["restaurant_image"],
tableId: json["table_id"],
tableName: json["table_name"],
branchName: json["branch_name"],
nexturl: json["nexturl"],
tableMenuList: List<TableMenuList>.from(
json["table_menu_list"].map((x) => TableMenuList.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"restaurant_id": restaurantId,
"restaurant_name": restaurantName,
"restaurant_image": restaurantImage,
"table_id": tableId,
"table_name": tableName,
"branch_name": branchName,
"nexturl": nexturl,
"table_menu_list":
List<dynamic>.from(tableMenuList.map((x) => x.toJson())),
};
}
class TableMenuList {
String menuCategory;
String menuCategoryId;
String menuCategoryImage;
String nexturl;
List<CategoryDish> categoryDishes;
TableMenuList({
this.menuCategory,
this.menuCategoryId,
this.menuCategoryImage,
this.nexturl,
this.categoryDishes,
});
factory TableMenuList.fromJson(Map<String, dynamic> json) => TableMenuList(
menuCategory: json["menu_category"],
menuCategoryId: json["menu_category_id"],
menuCategoryImage: json["menu_category_image"],
nexturl: json["nexturl"],
categoryDishes: List<CategoryDish>.from(
json["category_dishes"].map((x) => CategoryDish.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"menu_category": menuCategory,
"menu_category_id": menuCategoryId,
"menu_category_image": menuCategoryImage,
"nexturl": nexturl,
"category_dishes":
List<dynamic>.from(categoryDishes.map((x) => x.toJson())),
};
}
class AddonCat {
String addonCategory;
String addonCategoryId;
int addonSelection;
String nexturl;
List<CategoryDish> addons;
AddonCat({
this.addonCategory,
this.addonCategoryId,
this.addonSelection,
this.nexturl,
this.addons,
});
factory AddonCat.fromJson(Map<String, dynamic> json) => AddonCat(
addonCategory: json["addon_category"],
addonCategoryId: json["addon_category_id"],
addonSelection: json["addon_selection"],
nexturl: json["nexturl"],
addons: List<CategoryDish>.from(
json["addons"].map((x) => CategoryDish.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"addon_category": addonCategory,
"addon_category_id": addonCategoryId,
"addon_selection": addonSelection,
"nexturl": nexturl,
"addons": List<dynamic>.from(addons.map((x) => x.toJson())),
};
}
class CategoryDish {
String dishId;
String dishName;
double dishPrice;
String dishImage;
DishCurrency dishCurrency;
int dishCalories;
String dishDescription;
bool dishAvailability;
int dishType;
String nexturl;
List<AddonCat> addonCat;
CategoryDish({
this.dishId,
this.dishName,
this.dishPrice,
this.dishImage,
this.dishCurrency,
this.dishCalories,
this.dishDescription,
this.dishAvailability,
this.dishType,
this.nexturl,
this.addonCat,
});
factory CategoryDish.fromJson(Map<String, dynamic> json) => CategoryDish(
dishId: json["dish_id"],
dishName: json["dish_name"],
dishPrice: json["dish_price"].toDouble(),
dishImage: json["dish_image"],
dishCurrency: dishCurrencyValues.map[json["dish_currency"]],
dishCalories: json["dish_calories"],
dishDescription: json["dish_description"],
dishAvailability: json["dish_Availability"],
dishType: json["dish_Type"],
nexturl: json["nexturl"] == null ? null : json["nexturl"],
addonCat: json["addonCat"] == null
? null
: List<AddonCat>.from(
json["addonCat"].map((x) => AddonCat.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"dish_id": dishId,
"dish_name": dishName,
"dish_price": dishPrice,
"dish_image": dishImage,
"dish_currency": dishCurrencyValues.reverse[dishCurrency],
"dish_calories": dishCalories,
"dish_description": dishDescription,
"dish_Availability": dishAvailability,
"dish_Type": dishType,
"nexturl": nexturl == null ? null : nexturl,
"addonCat": addonCat == null
? null
: List<dynamic>.from(addonCat.map((x) => x.toJson())),
};
}
enum DishCurrency { SAR }
final dishCurrencyValues = EnumValues({"SAR": DishCurrency.SAR});
class EnumValues<T> {
Map<String, T> map;
Map<T, String> reverseMap;
EnumValues(this.map);
Map<T, String> get reverse {
if (reverseMap == null) {
reverseMap = map.map((k, v) => new MapEntry(v, k));
}
return reverseMap;
}
}
回答1:
I personally use this one for generating dart classes from JSON https://javiercbk.github.io/json_to_dart/
From my experience most of these automatic class builders are flawed to some extent and it is good practice to go over the generated dart manually. Or try your luck and walk the stack trace to see where parsing failed (usually when handling int and double from what I've seen).
Anyhow back to your problem, from looking at your code I see you are misusing indexes and generally having problems with json data structure:
title: Text(welcome[index]
.tableMenuList[index]
.categoryDishes[index]
.dishName),
The code above can easily throw "RangeError (index): Invalid value: Not in range..." (example if welcome[ 2 ] has only 1 tableMenuList). Even if all those arrays above are somehow the same length you would still not get the expected result.. The list would end up showing you 1st meal from the 1st menu list and 1st category dish, then next one would be 2nd meal from the 2nd menu and the 2nd restaurant.
Also because of the same reason as above the following code isn't enough:
itemCount: myData == null ? 0 : myData.length,
You need to have an itemCount for each of those lists you are using.
I've modified your code to work with the given JSON and changed a few things, in the end it looks like this.
I'm posting my source bellow, hopefully it will make things clearer for you:
pubspec.yaml
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^0.1.2
http: any
welcome_model.dart
class Welcome {
String restaurantId;
String restaurantName;
String restaurantImage;
String tableId;
String tableName;
String branchName;
String nexturl;
List<TableMenuList> tableMenuList;
Welcome(
{this.restaurantId,
this.restaurantName,
this.restaurantImage,
this.tableId,
this.tableName,
this.branchName,
this.nexturl,
this.tableMenuList});
Welcome.fromJson(Map<String, dynamic> json) {
restaurantId = json['restaurant_id'];
restaurantName = json['restaurant_name'];
restaurantImage = json['restaurant_image'];
tableId = json['table_id'];
tableName = json['table_name'];
branchName = json['branch_name'];
nexturl = json['nexturl'];
if (json['table_menu_list'] != null) {
tableMenuList = new List<TableMenuList>();
json['table_menu_list'].forEach((v) {
tableMenuList.add(new TableMenuList.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['restaurant_id'] = this.restaurantId;
data['restaurant_name'] = this.restaurantName;
data['restaurant_image'] = this.restaurantImage;
data['table_id'] = this.tableId;
data['table_name'] = this.tableName;
data['branch_name'] = this.branchName;
data['nexturl'] = this.nexturl;
if (this.tableMenuList != null) {
data['table_menu_list'] =
this.tableMenuList.map((v) => v.toJson()).toList();
}
return data;
}
}
class TableMenuList {
String menuCategory;
String menuCategoryId;
String menuCategoryImage;
String nexturl;
List<CategoryDishes> categoryDishes;
TableMenuList(
{this.menuCategory,
this.menuCategoryId,
this.menuCategoryImage,
this.nexturl,
this.categoryDishes});
TableMenuList.fromJson(Map<String, dynamic> json) {
menuCategory = json['menu_category'];
menuCategoryId = json['menu_category_id'];
menuCategoryImage = json['menu_category_image'];
nexturl = json['nexturl'];
if (json['category_dishes'] != null) {
categoryDishes = new List<CategoryDishes>();
json['category_dishes'].forEach((v) {
categoryDishes.add(new CategoryDishes.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['menu_category'] = this.menuCategory;
data['menu_category_id'] = this.menuCategoryId;
data['menu_category_image'] = this.menuCategoryImage;
data['nexturl'] = this.nexturl;
if (this.categoryDishes != null) {
data['category_dishes'] =
this.categoryDishes.map((v) => v.toJson()).toList();
}
return data;
}
}
class CategoryDishes {
String dishId;
String dishName;
double dishPrice;
String dishImage;
String dishCurrency;
double dishCalories;
String dishDescription;
bool dishAvailability;
int dishType;
String nexturl;
List<AddonCat> addonCat;
CategoryDishes(
{this.dishId,
this.dishName,
this.dishPrice,
this.dishImage,
this.dishCurrency,
this.dishCalories,
this.dishDescription,
this.dishAvailability,
this.dishType,
this.nexturl,
this.addonCat});
CategoryDishes.fromJson(Map<String, dynamic> json) {
dishId = json['dish_id'];
dishName = json['dish_name'];
dishPrice = json['dish_price'];
dishImage = json['dish_image'];
dishCurrency = json['dish_currency'];
dishCalories = json['dish_calories'];
dishDescription = json['dish_description'];
dishAvailability = json['dish_Availability'];
dishType = json['dish_Type'];
nexturl = json['nexturl'];
if (json['addonCat'] != null) {
addonCat = new List<AddonCat>();
json['addonCat'].forEach((v) {
addonCat.add(new AddonCat.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['dish_id'] = this.dishId;
data['dish_name'] = this.dishName;
data['dish_price'] = this.dishPrice;
data['dish_image'] = this.dishImage;
data['dish_currency'] = this.dishCurrency;
data['dish_calories'] = this.dishCalories;
data['dish_description'] = this.dishDescription;
data['dish_Availability'] = this.dishAvailability;
data['dish_Type'] = this.dishType;
data['nexturl'] = this.nexturl;
if (this.addonCat != null) {
data['addonCat'] = this.addonCat.map((v) => v.toJson()).toList();
}
return data;
}
}
class AddonCat {
String addonCategory;
String addonCategoryId;
int addonSelection;
String nexturl;
List<Addons> addons;
AddonCat(
{this.addonCategory,
this.addonCategoryId,
this.addonSelection,
this.nexturl,
this.addons});
AddonCat.fromJson(Map<String, dynamic> json) {
addonCategory = json['addon_category'];
addonCategoryId = json['addon_category_id'];
addonSelection = json['addon_selection'];
nexturl = json['nexturl'];
if (json['addons'] != null) {
addons = new List<Addons>();
json['addons'].forEach((v) {
addons.add(new Addons.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['addon_category'] = this.addonCategory;
data['addon_category_id'] = this.addonCategoryId;
data['addon_selection'] = this.addonSelection;
data['nexturl'] = this.nexturl;
if (this.addons != null) {
data['addons'] = this.addons.map((v) => v.toJson()).toList();
}
return data;
}
}
class Addons {
String dishId;
String dishName;
double dishPrice;
String dishImage;
String dishCurrency;
double dishCalories;
String dishDescription;
bool dishAvailability;
int dishType;
Addons(
{this.dishId,
this.dishName,
this.dishPrice,
this.dishImage,
this.dishCurrency,
this.dishCalories,
this.dishDescription,
this.dishAvailability,
this.dishType});
Addons.fromJson(Map<String, dynamic> json) {
dishId = json['dish_id'];
dishName = json['dish_name'];
dishPrice = json['dish_price'];
dishImage = json['dish_image'];
dishCurrency = json['dish_currency'];
dishCalories = json['dish_calories'];
dishDescription = json['dish_description'];
dishAvailability = json['dish_Availability'];
dishType = json['dish_Type'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['dish_id'] = this.dishId;
data['dish_name'] = this.dishName;
data['dish_price'] = this.dishPrice;
data['dish_image'] = this.dishImage;
data['dish_currency'] = this.dishCurrency;
data['dish_calories'] = this.dishCalories;
data['dish_description'] = this.dishDescription;
data['dish_Availability'] = this.dishAvailability;
data['dish_Type'] = this.dishType;
return data;
}
}
welcome_page.dart
import 'package:flutter/material.dart';
import 'welcome_model.dart';
import 'dart:async';
import 'dart:io';
import 'dart:convert';
import 'package:http/http.dart' as http;
class WelcomePage extends StatefulWidget {
@override
_WelcomePageState createState() => new _WelcomePageState();
}
class _WelcomePageState extends State<WelcomePage> {
List<Welcome> welcomeList;
bool isLoading = true;
int selectedRestaurantIndex = 0;
String titleString = "Restaurant";
@override
void initState() {
super.initState();
_fetchData();
}
@override
void setState(fn) {
if(mounted){
super.setState(fn);
}
}
@override
void dispose() {
super.dispose();
}
_fetchData() async{
setState(() {
isLoading = true;
});
// String url = Uri.encodeFull("http://www.mocky.io/v2/5dfccffc310000efc8d2c1ad"); // original json has only one restaurant
// the one bellow has 3 restaurants,
// 1st one was left untouched,
// 2nd one (Steak house) has only "From The Barnyard" and "Fast Food" menu types
// 3rd one (Bistro cafe) has only "Fresh From The Sea" and "Fast Food" menu types
String url = Uri.encodeFull("http://www.mocky.io/v2/5e4aa68c2f0000690097d3f6");
var parsedJson;
try {
http.Response response = await http.get(url).
timeout(Duration(seconds: 10));
if (response.statusCode == 200) {
if (response.bodyBytes != null) {
parsedJson = json.decode(utf8.decode(response.bodyBytes));
}
} else {
print('RESPONSE CODE != 200 !');
}
} on TimeoutException catch (e) {
print('Error: $e');
} on SocketException catch (e) {
print('Error: $e');
} on Error catch (e) {
print('Error: $e');
}
if(parsedJson!=null){
if(parsedJson.length>0){
welcomeList = new List<Welcome>();
for(int i=0; i<parsedJson.length; i++) {
try {
welcomeList.add(Welcome.fromJson(parsedJson[i]));
} catch (e, s){
print('Eroor parsing from JSON! For # $i');
print('Error: $e');
print('Stacktrace: $s');
}
}
if(welcomeList[0]!=null && welcomeList[0].restaurantName!=null) {
titleString = welcomeList[0].restaurantName;
}
}
}
setState(() {
isLoading = false;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
iconTheme: IconThemeData(
color: Colors.white,
),
title: Text(titleString),
centerTitle: true,
),
drawer: Drawer(
child: ListView(
padding: EdgeInsets.zero,
children: <Widget>[
DrawerHeader(
child: Text("Select a restaurant", style: TextStyle(color: Colors.white, fontSize: 28),textAlign: TextAlign.center,
),
decoration: BoxDecoration(
color: Theme.of(context).primaryColor,
),
),
(welcomeList!=null && welcomeList.length>0) ?
ListView.builder(
shrinkWrap: true,
physics: ClampingScrollPhysics(),
itemCount: welcomeList.length,
itemBuilder: (BuildContext context, int index) {
return Padding(
padding: EdgeInsets.all(8),
child: RaisedButton(
onPressed: () {
setState(() {
selectedRestaurantIndex = index;
titleString = welcomeList[index].restaurantName.toString();
});
Navigator.pop(context);
},
padding: EdgeInsets.all(12),
child: Text(welcomeList[index].restaurantName.toString()),
)
);
;}
)
: Text("No restaurants loaded...")
]
)
),
body: (isLoading)
? Center(child: CircularProgressIndicator(),)
: Container(
child: Center(
child: ListView.builder(
itemBuilder: (BuildContext context, int index1) {
return Card(
child: ListTile(
subtitle: Text(welcomeList[selectedRestaurantIndex].tableMenuList[index1].menuCategory.toString()),
title: ListView.builder(
shrinkWrap: true,
physics: ClampingScrollPhysics(),
itemBuilder: (BuildContext context, int index2) {
return Card(
child: ListTile(
title: Text(welcomeList[selectedRestaurantIndex].tableMenuList[index1].categoryDishes[index2].dishName.toString()),
));
},
itemCount: (welcomeList[selectedRestaurantIndex].tableMenuList[index1] == null || welcomeList[selectedRestaurantIndex].tableMenuList[index1].categoryDishes == null) ? 0 : (welcomeList[selectedRestaurantIndex].tableMenuList[index1].categoryDishes.length) ,)
)
);
},
itemCount: (welcomeList == null || welcomeList[selectedRestaurantIndex] == null || welcomeList[selectedRestaurantIndex].tableMenuList == null) ? 0 : (welcomeList[selectedRestaurantIndex].tableMenuList.length) ,
)
),
),
);
}
}
JSON with 3 restaurants here or here.
来源:https://stackoverflow.com/questions/60145694/type-listdynamic-is-not-a-subtype-of-type-string