DropdownButtonFormField gives Error when try to display String - flutter

I want to make DropdownButtonFormField that shows cities like this:
final List<String> cities = ['London', 'New York', 'Paris', 'Shanghahai', 'Tokyo'];
String _currentCity;
DropdownButtonFormField(
value: _currentCity ?? ' ',
decoration: textInputDecoration,
items: cities.map((city) {
return DropdownMenuItem(
value: city,
child: Text('$city City '),
);
}).toList(),
onChanged: (val) => setState(() => _currentCity = val ),
),
But when I try to show these Strings I get red screen error :
and If I changed the Strings inside the List to numbers it works well:
final List<String> cities = ['0', '1', '2', '3', '4'];
Can someone tell me what is wrong with it although I use List of strings

You can try set _currentCity for default value?
String _currentCity = 'London';

Related

How to get multiple values from an item selected in a searchable dropdownbox(from dropdown_search package) in Flutter?

I have a list where each item contains a title and two amounts. I also have a searchable dropdown box, from the package dropdown_search, which is supposed to contain the titles of the items in the list. When an item is selected in the dropdown box, I want to get that item's title and two amount values and set variables equal to them. However, with my current code, I am getting the error:
"The argument type 'List<String>' can't be assigned to the parameter type 'List<Food>'"
Here is my list and the variables I want to change when a dropdown item is selected:
final List<Food> foodListData = [
Food(
title: 'Food 1',
amount1: 0.0,
amount2: 8.0,
),
Food(
title: 'Food 2',
amount1: 7.0,
amount2: 3.0,
),
Food(
title: 'Food 3',
amount1: 0.5,
amount2: 0.0,
),
],
String Vtitle = '';
double Vamount1=0.0,
double Vamount2=0.0,
Here is my dropdown code:
DropdownSearch<Food>(
key: _popupBuilderKey,
items: foodListData.map((item) {
return item.title;
}).toList(),
popupProps: PopupProps.menu(
showSearchBox: true,
),
onChanged: (Food? foodListData) {
setState(() {
Vtitle = foodListData!.title;
Vamount1 = foodListData.amount1;
Vamount2 = foodListData.amount2;
});
}
)
The error is on the line:
foodListData.map((item) {
return item.title;
}).toList(),

Dart: Convert map (Key / Value) into an Ordered List[]

I'm receiving a document snapshot from firestore and I convert it into a Map<String, dynamic> and I know that maps are not ordered, however, I want to order the layout of my screen fields in a certain order. Problem is, the order that I want to achieve is not alphabetical. Here is a sample of my map:
Map<String, dynamic> customerInfo = {
'projectName': 'John Doe',
'state': 'Arizona',
'city': 'Tempe',
'estimate': 123000,
'geoLocation': '12.345678,23.456789'
}
So, I am sending this map to a loop to iterate over keys/values and converting them into a list of widgets, however, for some screens I need to have 'State' be the first widget, and 'City' be the second widget, and vice versa for other screens. Some maps will have more fields, those extra fields will not matter later on, I just want to maintain a certain order for certain fields if they exist.
I tried looping over the keys using a switch / if to match the keys and do a List<Widget>().add(Text(key, value)) however, the generated list is still unordered obviously. Here is a sample code of what I am trying to achieve:
class ProjectViews {
List<Widget> projectDetailedView(Map<String, dynamic> data) {
final List<Widget> fields = [];
fields.add(
Text(
data['projectName'],
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
color: constants.primaryTextColor,
),
textAlign: TextAlign.start,
),
);
data.forEach((key, value) {
if (key == 'state') {
fields.add(dataField(key, value));
} else if (key == 'city') {
fields.add(dataField(key, value));
} else if (key == 'estimate') {
fields.add(dataField(key, value));
}
// switch (key) {
// case 'state':
// fields.add(dataField(key, value));
// break;
// case 'city':
// fields.add(dataField(key, value));
// break;
// case 'estimate':
// fields.add(dataField(key, value));
// break;
// }
});
return fields;
}
Widget dataField(String key, dynamic value) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 4),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
key,
style: TextStyle(fontSize: 20),
),
Text(
value.toString(),
style: TextStyle(fontSize: 20),
),
],
),
);
}
}
I want to make sure the List<Widget> fields are added in a certain order. The received map may contain 5 elements or 20 elements, only some of those need to be in order.
Can I use a List<String> arranged as my preferred order and convert the map based on this list?
Any other options to achieve this please?
Thanks
So here is my solution to the problem, basically you create a new ordered map with only the field names that you want to display in the order of display, then you populate this new map with the data/widgets.
class ProjectViews {
List<Widget> projectDetailedView2(Map<String, dynamic> data) {
final List<Widget> fields = [];
final Map<String, dynamic> orderedFields = {
'state': '',
'city': '',
'geoLocation': '',
}; // this map has the items we want to display in the order we want
fields.add(
Text(
data['projectName'],
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
color: constants.primaryTextColor,
),
textAlign: TextAlign.start,
),
);
data.forEach((key, value) {
if (orderedFields.keys.contains(key)) {
orderedFields[key] = dataField(key, value);
}
});
orderedFields.forEach((key, value) {
if (value.runtimeType == Widget) {
fields.add(value);
}
});
return fields;
}
Maybe you can use a LinkedHashMap. It keeps the key insertion order.
FirebaseFirestore has a .orderBy() function that you can use to order your data when you query a collection.
QuerySnapshot<Map<String, dynamic>> snapshot =
await firestoreInstance.collection('collectionName')
.orderBy('value', descending: false)
.get();
Note: Your question seems like you're trying to get a list of Customer Info from firebase, so all you have to do is replace the 'collectionName' in my code with the name of the customer info collection. This is a querysnapshot because it queries the collection and gets you all the customer info in the collection.
You will also have to replace the 'Value' in my code here with the key of the value you want it to be ordered with. You can also choose whether it should be ascending or descending by setting the descending value to either true or false.
I hope this helps.

Change selection of dropdown button according to the choice from the previous one, Flutter

I have 2 DropdownButtonFormFields where I have a selection of cars. I need to change the second selection of buttons according to the car model user has chosen from the first selection in the DropdownButtonFormField (i.e. If a user chooses a Mercedes in the first one, in the DropdownButtonFormField below, I want to display only models of Mercedes and not, let's say, Audi).
How can I achieve this? Here is the code:
String _make, _model;
/// List of cars and models
List<String> carList = [
'Audi',
'BMW',
'Mercedes',
];
List<String> modelAudi = ['A6', 'A8', 'Q7',];
List<String> modelMercedes = ['E-Class', 'S-Class','Maybach'];
List<String> modelBMW = ['3-Series', 'X5', 'X7'];
/*two DropdownButtonFormFields, but the second one needs to match
it's car manufacturer selection from the carList selection
(i.e. if you select Audi, it must only show the modelAudi list (A6,
A8, Q7) in the second DropdownButtonFormField)
*/
DropdownButtonFormField<String>(
value: _make,
items: carList
.map((label) => DropdownMenuItem(
child: Text(label.toString()),
value: label,
))
.toList(),
onChanged: (value) {
setState(() {
_make = value;
print(value);
});
},
),
DropdownButtonFormField<String>(
value: _model,
/* here is where I need to implement logic
that maps out the model names that matches the car maker
*/
items: modelAudi
.map((label) => DropdownMenuItem(
child: Text(label.toString()),
value: label,
))
.toList(),
onChanged: (value) {
setState(() {
_model = value;
print(value);
});
},
),
The DropDown for the first button:
And naturally because I have no logic behind it, I get this as the model selection whatever I chose from the car list, but I want it to map out only models from the car list you chose.
This is a great use case for a switch statement. Define your cases for each car maker according to this example:
String _maker;
List chosenMakerModel;
switch (_maker) {
case 'Audi':
chosenMakerModel = modelAudi;
break;
case 'BMW':
// implement logic:
break;
case 'OTHER MANUFACTURER':
// implement logic;
break;
}
Using the example code above use chosenMakerModel instead of modelAudi
You can create a model selection method to handle this situation, like
List<String> _selectModel(String? modelName) {
return modelName == carList[0]
? modelAudi
: modelName == carList[1]
? modelMercedes
: modelBMW; // initally it will have modelBMW
}
This will decide the second dropdown item. If you click to select the second drop down item 1st, it will through errors. To handle this situation, you need to update the second dropdown value as well. You can set the second dropdown value=null. Therefor we need to use nullable String for selection value.
class MyProfileState extends State<StatefulWidget> {
String? _make, _model;
/// List of cars and models
List<String> carList = ['Audi', 'BMW', 'Mercedes'];
List<String> modelAudi = ['A6', 'A8', 'Q7'];
List<String> modelMercedes = ['E-Class', 'S-Class', 'Maybach'];
List<String> modelBMW = ['3-Series', 'X5', 'X7'];
List<String> _selectModel(String? modelName) {
return modelName == carList[0]
? modelAudi
: modelName == carList[1]
? modelMercedes
: modelBMW;
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
DropdownButtonFormField<String>(
value: _make,
items: carList
.map((label) => DropdownMenuItem(
child: Text(label.toString()),
value: label,
))
.toList(),
onChanged: (value) {
setState(() {
_make = value;
_model = null;
print(value);
});
},
),
DropdownButtonFormField<String>(
value: _model,
items: _selectModel(_make)
.map((label) => DropdownMenuItem(
child: Text(label.toString()),
value: label,
))
.toList(),
onChanged: (value) {
setState(() {
_model = value;
print(value);
});
},
),
],
));
}
}

Is it allowed to create more than 1 drop down menu in Bottom sheet flutter? I am getting an error

This is my String list:
final List<String> cupsize = ['Select', 'Small', 'Medium', 'Large'];
final List<String> flavour = [
'Chocolate',
'Vanilla',
'Strawberry',
'Blueberry',
'Raspberry',
'Kiwi'
'Select'
];
String _currentCupSize;
String _currentFlavour;
And The drop down menu function is as follows:
//This is for cupsize
DropdownButtonFormField(
value: _currentCupSize ?? 'Select',
items: cupsize.map((size) {
return DropdownMenuItem(
value: size,
child: Text('$size Size'),
);
}).toList(),
onChanged: (val) => setState(() {
return _currentCupSize = val;
}),
),
//This is for flavour
DropdownButtonFormField(
value: _currentFlavour ?? 'One',
items: flavour.map((flav) {
return DropdownMenuItem(
value: flav,
child: Text('$flav Flavour'),
);
}).toList(),
onChanged: (val) => setState(() {
return _currentFlavour = val;
}),
),
The cupsize code is working fine but as soon as flavor function is written,
It says:
I referred to some other answers but none solved my problem.
Any help will be much appreciated:)
Two issues I see here.
One is that you have missed a , after 'Kiwi' in the List.
Second, you have 'Select' in the flavour List. But then, your default value for your second DropdownButtonFormField is 'One'.
So either, change the default value to 'Select' or change the last value in the list to 'One';
final List<String> flavour = [
'Chocolate',
'Vanilla',
'Strawberry',
'Blueberry',
'Raspberry',
'Kiwi',
'One'
];
Since, it doesn't see your 'One' default value being in the list, it is throwing the error.

Flutter: Dropdownbutton does not update to display selected choice

I am trying to use a dropdown button to have the user select from a list of options, however after making a selection the dropdown button remains displaying the hint. I think something about the setState is not updating the dropdown button.
value: skillChoice,
items: listDrop,
hint: Text("Choose Skill"),
onChanged: (value) {
setState(() {
skillChoice = value;
});
},
),
here are the variables which are declared earlier in the code:
List<DropdownMenuItem<int>> listDrop = [];
int skillChoice = null;
Can anyone let me know why it isn't updating?
I think setting skillChoice null initially disables the dropdown.
It would have been better if you had shown the full code snippet of how you implemented your DropDownButton. But here is how I do implement mine:
// This is the initial value that will be selected on the DropDownMenu by default
String choice = '1';
// This is the List of String (or whatever data type you want) that will make up the
Drop Down Menu Item options. NOTE: That the String value of 'choice' ('1') is also present in the List of choices ('1')
List<String> choices = [
'1',
'2',
'3',
'4',
'5',
];
DropdownButton<String>(
value: choice,
icon: Icon(Icons.add),
onChanged: (String newValue) {
setState(() => choices = newValue);
},
items: choices.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(
value,
)
);
}).toList(),
),
Should work properly for you now.