Not able to prepopulate dropdown with object in flutter
3,455
Solution 1
Screenshot:
Code:
There were too many mistakes in your code, I just created a minimal reproducible code showing you what you want to achieve. You should use FutureBuilder
if you don't want to create a local dummy DropdownMenuItem
, for simplicity I created it.
class AddOrEditClaim extends StatefulWidget {
@override
AddOrEditClaimState createState() => AddOrEditClaimState();
}
class AddOrEditClaimState extends State<AddOrEditClaim> {
UserPackages _selectedPackage = UserPackages(categoryName: "vehicle insurance", packageId: "5675");
List<UserPackages> packageList = [];
@override
void initState() {
super.initState();
fetchPackages();
}
@override
Widget build(BuildContext context) {
var items = packageList.map((item) {
return DropdownMenuItem<UserPackages>(
child: Text(item.categoryName),
value: item,
);
}).toList();
// if list is empty, create a dummy item
if (items.isEmpty) {
items = [
DropdownMenuItem(
child: Text(_selectedPackage.categoryName),
value: _selectedPackage,
)
];
}
return Scaffold(
appBar: AppBar(title: Text('Add Claim')),
body: Center(
child: DropdownButton<UserPackages>(
items: items,
onChanged: (newVal) => setState(() => _selectedPackage = newVal!),
value: _selectedPackage,
),
),
);
}
void fetchPackages() async {
var resp = await http.get(Uri.parse('http://www.mocky.io/v2/5da94ca131000058004e0769'));
if (resp.statusCode == 200) {
setState(() {
packageList = parsePackages(resp.body);
_selectedPackage = packageList[0];
});
} else {
print("Error occurred");
}
}
List<UserPackages> parsePackages(String responseBody) {
final parsedJson = json.decode(responseBody);
final parsed = parsedJson.cast<Map<String, dynamic>>();
return parsed.map<UserPackages>((json) => UserPackages.fromJson(json)).toList();
}
}
class UserPackages {
final String categoryName;
final String packageId;
UserPackages({required this.categoryName, required this.packageId});
factory UserPackages.fromJson(Map<String, dynamic> json) {
return UserPackages(
packageId: json['packageId'] as String,
categoryName: json['categoryName'] as String,
);
}
}
Solution 2
add null / empty
check for packageList
. because packageList
is updaed after fetchPackages
network call is resolved so wrap that DropdownButton in a if block as below
Form(
key:formKey,
child:ListView(
children: <Widget>[
if(packageList.isNotEmpty){
new DropdownButton(
items: packageList.map((item) {
return new DropdownMenuItem<UserPackages>(
child: new Text(item.packageName),
value: item,
);
}).toList(),
onChanged: (newVal) {
setState(() {
selectedPckg = newVal;
});
},
value: selectedPckg ?? packageList[0],
),
}
])
)
Author by
sreeya chowdary
Updated on December 14, 2022Comments
-
sreeya chowdary over 1 year
I've a dropdown which is populated with objects received from API. The problem is I'm not able to pre-populate the dropdown with the object when the user takes edit.
Here is the sample JSON:
[{"_id":"435463","userId":"3423423","username":"ma","categoryId":"5656756","insurerId":"567544","packageId":"5675","categoryName":"vehicle insurance","insurerName":"lic","packageName":"family"}, {"_id":"4564644","userId":"2342344","username":"ma","categoryId":"6575744","insurerId":"567567","packageId":"3455","categoryName":"life insurance","insurerName":"lic","packageName":"family"}] `` import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; import 'package:intl/intl.dart'; import 'dart:convert'; UserPackages selectedPckg; class AddOrEditClaim extends StatefulWidget { @override AddOrEditClaimState createState() => AddOrEditClaimState(); } class AddOrEditClaimState extends State<AddOrEditClaim> { List<UserPackages> packageList = List(); final formKey = GlobalKey<FormState>(); @override void initState() { fetchPackages(); selectedPckg= UserPackages(); UserPackages packgToEdit = new UserPackages(); packgToEdit.packageId="123"; packgToEdit.packageName="family"; selectedPckg=packgToEdit; super.initState(); } @override Widget build(BuildContext context) { // TODO: implement build return new Scaffold( appBar: AppBar( title: Text('Add Claim'), ), body: Form( key:formKey, child:ListView( children: <Widget>[ new DropdownButton( items: packageList.map((item) { return new DropdownMenuItem<UserPackages>( child: new Text(item.packageName), value: item, ); }).toList(), onChanged: (newVal) { setState(() { selectedPckg = newVal; }); }, value: selectedPckg, ), ]) ) );; } fetchPackages() async { SharedPreferences prefs = await SharedPreferences.getInstance(); var resp = await http.get('http://www.mocky.io/v2/5da94ca131000058004e0769'); setState(() { packageList= parsePackages(resp.body); }); } List<UserPackages> parsePackages(String responseBody) { final parsedj = json.decode(responseBody); final parsed = parsedj.cast<Map<String, dynamic>>(); return parsed.map<UserPackages>((json) => UserPackages.fromJson(json)).toList(); } } Here is the Userpackages class: class UserPackages{ String packageName; String packageId; UserPackages({this.packageName,this.packageId}); factory UserPackages.fromJson(Map<String, dynamic> json){ return UserPackages( packageId:json['packageId'] as String, packageName: json['packageName'] as String, ); } } The following is being thrown 'package:flutter/src/material/dropdown.dart': Failed assertion: line 560 pos 15: 'items == null ||items.isEmpty || value == null || items.where((DropdownMenuItem<T> item) => item.value ==value).length == 1': is not true.
-
CopsOnRoad over 4 yearsTry this
value: selectedPckg ?? anyValidDefaultValue
, I'm not sure what yourselectedPcg
is, so you need to use any default value there. -
sreeya chowdary over 4 yearsselectedPckg is of type UserPackages @CopsOnRoad, I've edited the question to minimum reproducible state and included UserPackages class and API.
-
CopsOnRoad over 4 yearsHi, let me know if it didn't work, if worked please accept the answer. Thanks
-
-
nmanikiran over 4 yearsadd null check for
selectedPckg
at the drop-down value, so updated the code -
sreeya chowdary over 4 yearsthere's no change.
-
sreeya chowdary over 4 yearsThank you @CopsOnRoad for correcting the mistake but the issue here is that it's always initializing the drop down with packageList[0]
-
CopsOnRoad over 4 yearsYes, because I used
[0]
in the code, how do you want to initialize it when the data is ready? -
sreeya chowdary over 4 yearsI don't want to initialize the drop down with [0] but with '_selectedPackage' in init. Yes we're initializing in init but its not happening.
-
CopsOnRoad over 4 years@sreeyachowdary Ok, for that you can simply remove
_selectedPackage = packageList[0];
from above code, I will wait till you accept the answer :) -
sreeya chowdary over 4 yearsIf I remove that, 'items.isEmpty || value == null || items.where((DropdownMenuItem<T> item) => item.value == value).length == 1': is not true.' is being thrown.
-
CopsOnRoad over 4 yearsThat maybe because the item you're trying to add may not be on the server which is why I used first element (
0
index) when list is populated.