问题
Using the example in How to Create DropdownButton with a list of JSON Data and I want it to populate my DropDownButton in Flutter I have created the following working example:
main.dart
import 'package:flutter/material.dart';
import 'dart:convert';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
MyApp({Key key}) : super(key: key);
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final String jsonData =
'[{"id":"e20c","name":"Apples","type":"fruit"},{"id":"a24e","name":"Oranges","type":"fruit"},{"id":"f2a0","name":"Bananas","type":"fruit"}]';
List<FruitResponse> _fruitResponse = [];
String selectedName;
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
final json = JsonDecoder().convert(jsonData);
_fruitResponse = (json)
.map<FruitResponse>((item) => FruitResponse.fromJson(item))
.toList();
return MaterialApp(
title: 'Pick Fruit',
home: Scaffold(
appBar: AppBar(
title: Text("Pick Fruit"),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
DropdownButtonHideUnderline(
child: DropdownButton<String>(
hint: Text("Select Fruit"),
value: selectedName,
isDense: true,
onChanged: (String newValue) {
setState(() {
selectedName = newValue;
});
print(selectedName);
},
items: _fruitResponse.map((FruitResponse map) {
return DropdownMenuItem<String>(
value: map.nameDescription,
child: Text(map.nameDescription),
);
}).toList(),
)),
],
),
),
));
}
}
class FruitResponse {
final String nameid;
final String nameDescription;
FruitResponse({this.nameid, this.nameDescription});
factory FruitResponse.fromJson(Map<String, dynamic> json) {
return new FruitResponse(nameid: json['id'], nameDescription: json['name']);
}
}
However, my JSON data will be
{"objects":[{"id":"e20c","name":"Apples","type":"fruit"},{"id":"a24e","name":"Oranges","type":"fruit"},{"id":"f2a0","name":"Bananas","type":"fruit"}],"from":1,"to":3,"total":3}
I have used https://app.quicktype.io/ to generate the following
FruitResponse fruitResponseFromJson(String str) => FruitResponse.fromJson(json.decode(str));
String fruitResponseToJson(FruitResponse data) => json.encode(data.toJson());
class FruitResponse {
List<Object> objects;
int from;
int to;
int total;
FruitResponse({
this.objects,
this.from,
this.to,
this.total,
});
factory FruitResponse.fromJson(Map<String, dynamic> json) => FruitResponse(
objects: List<Object>.from(json["objects"].map((x) => Object.fromJson(x))),
from: json["from"],
to: json["to"],
total: json["total"],
);
Map<String, dynamic> toJson() => {
"objects": List<dynamic>.from(objects.map((x) => x.toJson())),
"from": from,
"to": to,
"total": total,
};
}
class Object {
String id;
String name;
String type;
Object({
this.id,
this.name,
this.type,
});
factory Object.fromJson(Map<String, dynamic> json) => Object(
id: json["id"],
name: json["name"],
type: json["type"],
);
Map<String, dynamic> toJson() => {
"id": id,
"name": name,
"type": type,
};
}
When I replace the class FruitResponse with the updated class FruitResponse and make changes to the items map I get an error.
Class '_InternalLinkedHashMap' has no instance method 'map' with matching
Working example in DartPad here https://dartpad.dev/b54d896aa35c159cd1749d5c67db7d52
Non-working example in DartPad here https://dartpad.dev/0413fb4bb7944ccd378b9eabf4e88ff3
I think the problem is just getting the List<Object> names correctly from the json data and using it in the DropDownButton items value. I know that map.objects.toString() is not correct, but I don't know what to put there or if I am missing something with _fruitResponse.
Thanks in advance for any help. I'm struggling with understanding mapping JSON response list data.
回答1:
Just Check out the following example i have created using the json, i have parsed the json locally :
Following is the json :
{
"objects": [
{
"id": "e20c",
"name": "Apples",
"type": "fruit"
},
{
"id": "a24e",
"name": "Oranges",
"type": "fruit"
},
{
"id": "f2a0",
"name": "Bananas",
"type": "fruit"
}
],
"from": 1,
"to": 3,
"total": 3
}
Depending on the json i have created the model class :
// To parse this JSON data, do
//
// final fruitResponse = fruitResponseFromJson(jsonString);
import 'dart:convert';
FruitResponse fruitResponseFromJson(String str) => FruitResponse.fromJson(json.decode(str));
String fruitResponseToJson(FruitResponse data) => json.encode(data.toJson());
class FruitResponse {
List<Object> objects;
int from;
int to;
int total;
FruitResponse({
this.objects,
this.from,
this.to,
this.total,
});
factory FruitResponse.fromJson(Map<String, dynamic> json) => FruitResponse(
objects: List<Object>.from(json["objects"].map((x) => Object.fromJson(x))),
from: json["from"],
to: json["to"],
total: json["total"],
);
Map<String, dynamic> toJson() => {
"objects": List<dynamic>.from(objects.map((x) => x.toJson())),
"from": from,
"to": to,
"total": total,
};
}
class Object {
String id;
String name;
String type;
Object({
this.id,
this.name,
this.type,
});
factory Object.fromJson(Map<String, dynamic> json) => Object(
id: json["id"],
name: json["name"],
type: json["type"],
);
Map<String, dynamic> toJson() => {
"id": id,
"name": name,
"type": type,
};
}
And later the main class where the i have defined the dropdown :
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'dummy.dart';
main() => runApp(MyApp());
class MyApp extends StatefulWidget {
@override
_UploadImageState createState() => _UploadImageState();
}
class _UploadImageState extends State<MyApp> {
bool _isLoading = false;
List<Object> objectList = List();
Future<String> loadFromAssets() async {
return await rootBundle.loadString('json/parse.json');
}
@override
void initState() {
// TODO: implement initState
super.initState();
loadYourData();
}
loadYourData() async {
setState(() {
_isLoading = true;
});
String jsonString = await loadFromAssets();
final fruitResponse = fruitResponseFromJson(jsonString);
objectList = fruitResponse.objects;
setState(() {
_isLoading = true;
});
}
@override
Widget build(BuildContext context) {
String selectedFruit;
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: Container(
child: Padding(
padding: const EdgeInsets.all(30.0),
child: Container(
height: 50,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5.0),
border: Border.all(
color: Colors.red, style: BorderStyle.solid, width: 0.80),
),
child: DropdownButton(
value: selectedFruit,
isExpanded: true,
icon: Padding(
padding: const EdgeInsets.only(left: 15.0),
child: Icon(Icons.arrow_drop_down),
),
iconSize: 25,
underline: SizedBox(),
onChanged: (newValue) {
setState(() {
print(newValue);
selectedFruit = newValue;
});
print(selectedFruit);
},
hint: Padding(
padding: const EdgeInsets.all(8.0),
child: Text('Select'),
),
items: objectList.map((data) {
return DropdownMenuItem(
value: data.id.toString(),
child: Padding(
padding: const EdgeInsets.only(left: 10.0),
child: Text(
data.name,
style: TextStyle(
fontSize: 18,
color: Colors.black,
),
),
),
);
}).toList()),
),
),
),
),
),
);
}
}
回答2:
I give u the idea, you must to change the String to Object
Replace DropdownButton to DropdownButton Where FruitResponse is the OBject that you want to use.
And
Replace onChanged: (String newValue) {
setState(() {
selectedName = newValue;
});
print(selectedName);
}
to
onChanged: (FruitResponse newValue) {
setState(() {
selectedName = newValue.nameid;
});
print(selectedName);
}
And DropdownMenuItem to DropdownMenuItem
回答3:
For example listaCatalogo.partes is a list of Object:
List<DropdownMenuItem<Catalogo>> _itemsPartes() {
var provider = Provider.of<CatalogNotifier>(context);
return provider.listaCatalogo.partes
.map((item) => DropdownMenuItem<Catalogo>(
value: item,
child: Text(item.valor),
))
.toList();
}
DropdownButton<Catalogo>(
value: registro.parteCat,
onChanged: (Catalogo value) {
setState(() {
registro.parteCat = value;
registro.parte = value.id;
});
},
items: _itemsPartes(),
)
来源:https://stackoverflow.com/questions/60419639/how-to-create-dropdownbutton-with-a-list-of-json-data-within-a-list-in-flutter