I need the user to select a value from a DropDown menu. Based on the value selected, a second DropDown is populated with values from the DB. I tried the following approach and it works when the user selects a value for the first time.
First DropDown:
DropdownButton<String>(
hint: Text('Please select your State/UT'),
style: TextStyle(color: kPrimaryGrey),
focusColor: kPrimaryBlue,
value: selectedState,
items: states.map((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
onChanged: (val) {
setState(() {
selectedState = val;
});
}),
SizedBox(
height: 25.0,
),
selectedState == null
? SizedBox(
height: 0.0,
)
: CampusSelector(
inputState: selectedState,
),
Second DropDown Using a FutureBuilder (SearchableDropdown):
class CampusSelector extends StatefulWidget {
final String inputState;
CampusSelector({this.inputState});
@override
_CampusSelectorState createState() => _CampusSelectorState();
}
class _CampusSelectorState extends State<CampusSelector> {
var allInstitutions = {};
QuerySnapshot stateData;
List<DropdownMenuItem> listOfDistricts = [];
List<DropdownMenuItem> listOfInstitutions = [];
List<DropdownMenuItem> listOfInsAndDisTmp = [];
List<DropdownMenuItem> listOfInsAndDis = [];
Future<void> getStateData;
List<String> institutions = [];
Future<void> fetchInstitutions(inputState) async {
List<String> institutionsTmp = [];
listOfInstitutions = [];
List<InstitutionAndDistrict> institutionsAndLocation = [];
stateData = await _db
.collection('institutions')
.where('STATE', isEqualTo: inputState)
.getDocuments();
for (int i = 0; i < stateData.documents.length; i++) {
String ins = stateData.documents[i].data['NAME_OF_INSTITUTION'];
String dis = stateData.documents[i].data['DISTRICT'];
institutionsTmp.add(stateData.documents[i].data['NAME_OF_INSTITUTION']);
institutionsAndLocation
.add(InstitutionAndDistrict(institution: ins, district: dis));
}
// Deduplication and Sorting
institutions = institutionsTmp.toSet().toList();
institutions.sort((a, b) => a.toString().compareTo(b.toString()));
debugPrint(institutions.toString());
for (int i = 0; i < institutions.length; i++) {
listOfInstitutions.add(DropdownMenuItem(
child: Text(institutions[i]),
value: institutions[i],
));
}
for (int i = 0; i < institutionsAndLocation.length; i++) {
listOfInsAndDisTmp.add(DropdownMenuItem(
child: ListTile(
title: Text(institutionsAndLocation[i].institution),
subtitle: Text(institutionsAndLocation[i].district),
),
value: institutionsAndLocation[i].institution,
));
}
setState(() {
listOfInsAndDis = listOfInsAndDisTmp;
});
}
@override
void initState() {
getStateData = fetchInstitutions(selectedState);
super.initState();
}
@override
Widget build(BuildContext context) {
return FutureBuilder(
future: getStateData,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return SearchableDropdown.single(
items: listOfInsAndDis,
value: selectedInstitution,
hint: "Please select your college/university",
searchHint: "Select one",
onChanged: (value) {
setState(() {
selectedInstitution = value;
for (int i = 0; i < stateData.documents.length; i++) {
if (stateData.documents[i].data['NAME_OF_INSTITUTION'] ==
value) {
selectedDistrict =
stateData.documents[i].data['DISTRICT'];
}
}
print(selectedInstitution);
print(selectedDistrict);
});
},
isExpanded: true,
);
} else {
return SizedBox(
height: 0.0,
);
}
});
}
}
CampusSelector class is still a work-in-progress, hence the unruly bunch of lists to process the data.
You populate your CampusBuilder class once in initState
. If you want to populate it with different data on each build
, you need to call the fetchInstitutions
methods in the build
method.
That will probably mean you have to use a FutureBuilder
.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.