How to use DropDownButton for dynamic list in flutter? - flutter

I am trying to implement dynamic dropdownButton in my app where the items of dropdown is going to come from the names of columns in my excel sheet. I am able to show all the columns of excel but I couldn't able to trace the index of column which the user is selecting from the dropdown.
I tried to make a map of dropdownitems like this in which the key is the index and value is the DropdownMenuItem like this :
late int selectedIndex; //where I want to store the selected index
late String initialDropDownVal;
List<Map<int,DropdownMenuItem<String>>> dropdownItems = [];
Then I added some values by iterating the columns of excel using a for loop :
excel = Excel.decodeBytes(bytes);
sheet = excel['Sheet1'];
for(int i = 1; i< sheet.maxCols; ++i){
var cell = sheet.cell(CellIndex.indexByColumnRow(rowIndex: 0, columnIndex: i));
String val = cell.value.toString();
if(val=="null"){
break;
}else{
if(i==1){
initialDropDownVal = val;
}
var newItem = DropdownMenuItem(
child: Text(val),
value: val,
);
dropdownItems.add({i:newItem});
}
}
But I could not able to map the values in items attribute of DropdownButton, I tried to implement like this but this is throwing error
DropdownButton(
value: selectedVal,
icon: const Icon(Icons.keyboard_arrow_down),
items: dropdownItems.map((int i,DropdownMenuItem<String> p) => p).toList(),
onChanged: (String? value){
setState(() {
initialDropDownVal = value!;
});
})
And I am not sure how to change set the selectedIndex in onChanged function. Please help me in this. Thanks

late int selectedIndex; //where I want to store the selected index
late String initialDropDownVal;
List<DropdownMenuItem<String>> dropdownItems = [];
excel = Excel.decodeBytes(bytes);
sheet = excel['Sheet1'];
for(int i = 1; i< sheet.maxCols; ++i){
var cell = sheet.cell(CellIndex.indexByColumnRow(rowIndex: 0, columnIndex: i));
String val = cell.value.toString();
if(val=="null"){
break;
}else{
if(i==1){
initialDropDownVal = val;
}
var newItem = DropdownMenuItem(
child: Text(val),
value: val,
);
dropdownItems.add(newItem);
}
}
DropdownButton(
value: selectedVal,
icon: const Icon(Icons.keyboard_arrow_down),
items: dropdownItems,
onChanged: (String? value){
setState(() {
initialDropDownVal = value!;
selectedIndex=dropdownItems.indexWhere((i)=>i.value==value);
});
})

late int selectedIndex; //where I want to store the selected index
late String initialDropDownVal;
List<Map<String,int>> dropdownItems = [];
excel = Excel.decodeBytes(bytes);
sheet = excel['Sheet1'];
for(int i = 1; i< sheet.maxCols; ++i){
var cell = sheet.cell(CellIndex.indexByColumnRow(rowIndex: 0, columnIndex: i));
String val = cell.value.toString();
if(val=="null"){
break;
}else{
if(i==1){
initialDropDownVal = val;
}
dropdownItems.add({val:i});
}
}
DropdownButton(
value: selectedVal,
icon: const Icon(Icons.keyboard_arrow_down),
items: dropdownItems.map((e) {
return DropdownMenuItem(
child: Text(e.keys.first),
value: e.keys.first,
);
}).toList(),
onChanged: (String? value){
setState(() {
initialDropDownVal = value!;
for(int i = 0; i< dropdownItems.length; ++i){
if(dropdownItems[i].keys.first==value){
setState(() {
selectedIndex = dropdownItems[i].values.first;
});
break;
}
}
});
}),
)

Related

How to Set Default Value by Condition in DropdownButtonFormField in Flutter?

I Have DropdownButtonFormField as Below.
CaseReasonModel? dropdownValueCaseReason;
List<DropdownMenuItem<CaseReasonModel>> items = [];
dropDownModels.forEach((element) {
items.add(DropdownMenuItem(
child: Text(
element.reasonName!,
style: Themes.getTextStyle(context),
),
value: element,
));
});
DropdownButtonFormField<CaseReasonModel>(
style: Themes.getTextFieldTextStyle(context),
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText:
AppLocalizations.of(context).hintSelectCaseReason,
),
value: dropdownValueCaseReason,
isExpanded: true,
items: items,
onChanged: (value) {
setState(() {
dropdownValueCaseReason = value;
});
},
),
And CaseReasionModel Class as below.
class CaseReasonModel {
String? reasonName;
String? reasonId;
String? reasonStatus;
static CaseReasonModel? fromHashMap(dynamic map) {
if (map == null) return null;
CaseReasonModel result = new CaseReasonModel();
result.reasonName = map["name"];
result.reasonId = map["reasonId"].toString();
result.reasonStatus = map["status"];
return result;
}
static List<CaseReasonModel> fromArrayOfHashMap(dynamic jsonArray) {
List<CaseReasonModel> list = [];
if (jsonArray != null) {
for (var jsonObject in jsonArray) {
list.add(fromHashMap(jsonObject)!);
}
}
return list;
}
}
I got all Reason in Drop-down, So here i have to set default selected value based on reason id which i specified. Suppose i have to set value which id = 2,
so how can I do this ?.

How to reset second drop down list if i change first drop down value?

I have two drop down which second is depends on first.
When i changing the first drop down value after selecting second dropdown value it throws an error as below.
So how to reset second drop down list if i changing first drop down value?
Drop down buttons are as below.
DropdownButtonFormField<Standard>(
validator: (value) {
if (value == null) {
return "Select Standard";
}
},
isExpanded: true,
hint: Text('Select Standard'),
value: selectedStandard,
items: _standards.map((Standard standard) {
return DropdownMenuItem<Standard>(
value: standard,
child: Text(standard.standardName),
);
}).toList(),
onChanged: (val) {
setState(() {
selectedStandard = val;
standardId = val?.standardId;
onMediumChange(val);
});
}),
SizedBox(height: 20),
DropdownButtonFormField<Medium>(
validator: (value) {
if (value == null) {
return "Select Medium";
}
},
isExpanded: true,
hint: Text('Select Medium'),
value: selectedMedium,
items: _mediums.map((Medium medium) {
return DropdownMenuItem<Medium>(
value: medium,
child: Text(medium.mediumName),
);
}).toList(),
onChanged: (val) {
setState(() {
selectedMedium = val;
mediumId = val?.mediumId;
});
}),
And get Values code is as below. Varibles which i used.
var _standards = <Standard>[];
var _mediums = <Medium>[];
Standard? selectedStandard;
Medium? selectedMedium;
#override
void initState() {
super.initState();
ApiManager().getStandards().then((standards) {
setState(() {
_standards = standards;
});
});
}
void onMediumChange(standard) {
setState(() {
selectedStandard = standard;
_mediums = [];
});
String mediumUrl =
"$baseUrl/medium/get_by_course_id?standard_id=${selectedStandard?.standardId}";
ApiManager().getMediums(mediumUrl).then((List<Medium> value) => {
setState(() {
_mediums = value;
})
});
}
As I understand there is a problem with selectedMedium
Try change Make it selectedMedium null inside onMediumChange
void onMediumChange(standard) {
setState(() {
selectedMedium = null;
selectedStandard = standard;
_mediums = [];
});
String mediumUrl =
"$baseUrl/medium/get_by_course_id?standard_id=${selectedStandard?.standardId}";
ApiManager().getMediums(mediumUrl).then((List<Medium> value) => {
setState(() {
_mediums = value;
})
});
}
first, check the values in _mediums because you must have a different value of selectedMedium here as according to this error !!!

All dropdown update when one is updated || flutter ||

I have a code wherein i am using listview.builder to create different dropdown menu items, the problem i am facing is, all the items in different dropdown menu updates when any one is updated.
i have attached my code down below. Your help to fix this would be highly appreciated.
I have also attached a screenshot of what exactly is happening for easier understanding. enter image description here
StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance
.collection(
'${widget.destination}rates'.toLowerCase())
.snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Text('Loading..');
} else {
List<DropdownMenuItem> tourName = [];
var selectedTour =
List(int.parse(widget.duration) + 1);
for (int i = 0;
i < snapshot.data.docs.length;
i++) {
DocumentSnapshot snap = snapshot.data.docs[i];
tourName.add(
DropdownMenuItem(
child: Text(snap['name']),
value: '${snap['name']}',
),
);
}
return DropdownButton(
items: tourName,
onChanged: (value) {
setState(() {
selectedTour[i] = value;
print(selectedTour);
});
},
value: selectedTour[i],
isExpanded: true,
hint: Text('Select Tour'),
);
}
},
),
You share the same variable selectedTour to all your tiles.
So when you update the selection :
setState(() {
selectedTour = value;
});
It will update everywhere selectedTour is used to display the value selected.
You can either use a new local variable :
} else {
List<DropdownMenuItem> tourName = [];
var selectedTourLocal = null;
for (int i = 0; i < snapshot.data.docs.length; i++)
...
setState(() {
selectedTourLocal = value;
});
...
value: selectedTourLocal,
Or use an array to store the values to the corresponding day.
// declare your array
selectedTour = new List(widget.duration);
...
setState(() {
selectedTour[i] = value;
});
...
value: selectedTour[i],

Flutter: Add value to LIst triggers RangeError (index)

Via this function, I add that much DataRows the user chooses in the UI. What I want to do is that the choosen value of the first row is the first value of the "besetzungsList" and the choosen value of the second row is the second value of the List and so on. And if a new value in the first row is choosen I want to replace the value.
addAufgabe() {
print(besetzungsList);
if (aufgabe.text.isNotEmpty || zeit.text.isNotEmpty) {
setState(() {});
if (event != null) {
...
} else {
for (var i = 0; i < currentValue; i++) {
aufgabenList.add(aufgabe.text);
zeitList.add(zeit.text);
dataTableRows.add(
DataRow(
cells: [
DataCell(Text(aufgabe.text), onTap: () {
removeRow(i);
}),
DataCell(Text(zeit.text), onTap: () {
removeRow(i);
}),
DataCell(DropDown(
hint: "Wählen",
users: users,
besetzungsListChanged: (String value) {
for (var j = 0; j < dataTableRows.length; j++) {
setState(() {
besetzungsList[j] = value;
});
}
// }
},
fromDropDown: (bool value) => fromDropDown = value,
))
],
),
);
}
}
}
It seems you remove an Element at i and add one at same index which is the cause.
You should do it the other way around...
besetzungsList.insert(i, value);
besetzungsList.removeAt(i + 1);

Cant Update Array With Dropdown Button And Future Flutter

I am using a dropdown button to update locations of restaurants around a user but, the locations aren't updating in the ListView. Here is what I have so far:
Edit: Added Init statement
Init Statement
#override
void initState() {
_dropDownMenuItems = buildAndGetDropDownMenuItems(changeDistance);
_mapDropdownFilter = _dropDownMenuItems[0].value;
filterMarker(userLat, userLong, dispensaries, 1);
super.initState();
}
I set up a class to assist with this called locations
class Locations{
final Restaurant dis;
final double dist;
final int index;
Locations({this.dis, this.dist, this.index});
}
Then call this filter to sort my location by distance and give them a distance in miles from user:
Future filterMarker(userLat, userLong, restaurants, filterdis) async {
Set<Marker> _tmpMarkers = Set();
final Uint8List markerIcon =
await getBytesFromAsset('assets/smiley.png', 100);
int filterCounter = 0;
List<Locations> _tmpLocation = List();
for (int i = 0; i < restaurant.length; ++i) {
Geolocator()
.distanceBetween(
userLat, userLong, restaurants[i].lat, restaurants[i].long)
.then((calcDist) {
print(calcDist);
if (calcDist / 1000 < filterdis) {
filterCounter++;
final String markerIdVal = 'marker_id_$filterCounter';
final MarkerId markerId = MarkerId(markerIdVal);
var dis = calcDist / 1000;
var distances = dis.toStringAsFixed(2);
// creating a new MARKER
_tmpMarkers.add(Marker(
markerId: markerId,
position: LatLng(restaurants[i].lat, restaurants[i].long),
infoWindow: InfoWindow(
title: restaurants[i].name, snippet: '$distances mi Away'),
icon: BitmapDescriptor.fromBytes(markerIcon)));
_tmpLocation.add(
Locations(index: i, dis: restaurants[i], dist: calcDist / 1000));
}
});
setState(() {
_filteredMarkers = _tmpMarkers;
filteredVenues = _tmpLocation.cast<Locations>();
});
print('Do once');
}
print('There are ${filteredVenues.length} _filteredMarkers');
}
My drop down button button is setup like this:
DropdownButton(
style: TextStyle(
fontFamily: 'Roboto-Regular',
color: Colors.black),
elevation: 6,
icon: Icon(
FontAwesomeIcons.angleRight,
color: buddiesGreen,
),
value: _mapDropdownFilter,
items: _dropDownMenuItems,
onChanged: _changeFilterList,
)
Filled with this:
//Distance Map filter Button
final List changeDistance = ['1', '5 ', '10 ', '20'];
// Set<Marker> _filteredMarkers = Set();
List<Locations> filteredVenues;
var _filteredMarkers;
var filteredRestaurant;
_dropDownMenuItems = buildAndGetDropDownMenuItems(changeDistance);
_mapDropdownFilter = _dropDownMenuItems[0].value;
String _mapDropdownFilter;
List<DropdownMenuItem<String>> _dropDownMenuItems;
List<DropdownMenuItem<String>> buildAndGetDropDownMenuItems(List tempList) {
List<DropdownMenuItem<String>> items = List();
for (String x in tempList) {
items.add(DropdownMenuItem(
value: x,
child: Text(
x,
style: TextStyle(
fontSize: 14,
fontFamily: 'Roboto-Regular',
fontWeight: FontWeight.w700,
color: buddiesPurple),
)));
}
return items;
}
void _changeFilterList(String value) {
//use _filterDropdown for switch statement
setState(() {
_mapDropdownFilter = value;
});
_sortProductsDropDown(_mapDropdownFilter);
print(_mapDropdownFilter);
}
void _sortProductsDropDown(_mapDropdownFilter) {
switch (_mapDropdownFilter) {
case '1 Mile':
print('1 Mile');
filterMarker(userLat, userLong, restaurant, 1);
print(restaurant.length);
break;
case '5 Miles':
filterMarker(userLat, userLong, restaurant, 5);
print(restaurant.length);
break;
case '10 Miles':
filterMarker(userLat, userLong, restaurant, 10);
print(restaurant.length);
break;
case '20 Miles':
filterMarker(userLat, userLong, restaurant, 20);
print(restaurant.length);
break;
}
}
It doesn't update when I hit the dropdown where is the disconnect and why doesn't it up date when the user selects different distances.
because you're not using setState() in initState() where you're fetching the list of locations. So the state of Locations isn't updated even though you fetch everything correctly.
..
setState(){
_dropDownMenuItems = buildAndGetDropDownMenuItems(changeDistance);
..
}
do something like this.