So for now i have a dropdown that i fetch from api. Here is what i do
Future<String> getSWData() async {
var res = await http.get(
Uri.encodeFull(Configuration.url + "api/getCategories"),
headers: {"Accept": "application/json"});
var resBody = json.decode(res.body);
setState(() {
data = resBody;
});
print(data);
return "Sucess";
}
then here is how i use it on dropdown
DropdownButtonHideUnderline(
child: new DropdownButton(
hint: new Text("Choose Category"),
items: data.map((item) {
return new DropdownMenuItem(
child: new Text(item['categoryName']),
value: item['categoryId'].toString(),
);
}).toList(),
onChanged: (newVal) {
setState(() {
mySelection = newVal;
});
},
value: _mySelection, ),),
Everything is working fine, but now i want to add All Category to my dropdown as an option, how can i achieve that ? thanks in advance
Your DropdownButton items is a list, so you can add to that list using ..add
DropdownButtonHideUnderline(
child: new DropdownButton(
hint: new Text("Choose Category"),
items: data.map((item) {
return new DropdownMenuItem(
child: new Text(item['categoryName']),
value: item['categoryId'].toString(),
);
}).toList()
..add(DropdownMenuItem(child: Text("All Category"), value: 'allcategory')),
onChanged: (newVal) {
setState(() {
mySelection = newVal;
});
},
value: _mySelection, ),),
You can use Cascade operator
DropdownButtonHideUnderline(
child: new DropdownButton(
hint: new Text("Choose Category"),
items: data..add({
'categoryName': 'All Categories',
'categoryId': 'AllCategories',
}).map((item) {
return new DropdownMenuItem(
child: new Text(item['categoryName']),
value: item['categoryId'].toString(),
);
}).toList(),
onChanged: (newVal) {
setState(() {
mySelection = newVal;
});
},
value: _mySelection, ),),
this solution will have the effect that "All Categories" item will be last.
You can add "All Categories" item in getSWData().
...
setState(() {
data = List();
data.add({
'categoryName': 'All Categories',
'categoryId': 'AllCategories',
});
data.addAll(resBody);
});
...
I would recommend the second approach, you get better readable code.
Related
I got issue to display value after select option... It always display Type All. I've follow from this answer but still got the problem.
DropdownButton(
hint: Text('Filter All Type'),
value: _typeDataL,
onChanged: (_newValue) {
setState(() {
_typeDataL = _newValue;
// print(typeDataL);
});
print(_newValue);
},
items: typeDataL.map((value) {
return DropdownMenuItem(
value: value,
child: new Text(value),
);
}).toList(),
),
try below code,
String? selectedValue = "Your init value";
var typeDataL = ["Your init value", "Option1", "Option2", "Option3"];
DropdownButton(
hint: const Text('Filter All Type'),
value: selectedValue,
onChanged: (newValue) {
setState(() {
selectedValue = newValue;
});
},
items: typeDataL.map((value) {
return DropdownMenuItem(
value: value,
child: Text(value),
);
}).toList(),
),
Your valueList should contain initial value, same as initial selectedValue and valueList should not contain duplicate values.
I try to make a dropdown taking data from firestore, after selecting the items from DromdownMenuItem the selected new value cannot display please help..?
DropdownButtonHideUnderline(
child: DropdownButton<String>(
isDense: true,
//isExpanded: false,
value: projectName,
onChanged: (String? newValue) {
debugPrint('selected onchange: $newValue');
setState(
() {
debugPrint('make selected: $newValue');
projectName = newValue.toString();
state.didChange(newValue);
setDefaultMake = false;
///var setDefaultMakeModel = true;
controllerProjectName.text = newValue.toString();
},
);
},
items: snapshot.data!.docs.map((value) {
return DropdownMenuItem<String>(
value: value.get('project_name'),
child: Text('${value.get('project_name')}'),
);
}).toList(),
),
),
My dropDown working fine, instead of Today as a string in the dropDown initial value I want Today's date-time using the property DateTime.now()
String dropdownvalue = 'Today';
var items = [
'Today',
'Choose from calendar',
];
My dropdown:
DropdownButton(
underline: Container(),
isExpanded: true,
value: dropdownvalue,
icon: const Icon(
Icons.keyboard_arrow_down,
color: Color(0xffB50000),
),
items: items.map((String items) {
return DropdownMenuItem(
value: items,
child: Text(
items,
style: TextStyle(
color: Color(0xffB50000),
fontWeight: FontWeight.w400),
),
);
}).toList(),
onChanged: (String? newValue) {
setState(() {
dropdownvalue = newValue!;
});
if(dropdownvalue =='Choose from calendar'){
setState(() {
_selectedDate(context);
});
}
if(dropdownvalue =='Today'){
setState(() {
String today = DateFormat('dd-MM-yyyy').format(currentDateTime);
print("today");
print(today);
final storeProvider = Provider.of<StorageProvider>(context, listen: false);
storeProvider.updateAppointmentDate(today);
final slotBookingProvider = Provider.of<SlotBookingProvider>(context, listen: false);
slotBookingProvider.checkAvailableSlot(date: today, context: context);
});
}
},
),
You can
You can replace replacing Today with DateTime.now().toString()
String? dropdownvalue;
var items = [
DateTime.now().toString(),
'Choose from calendar',
];
I have tried to use a function and for in loop to loop through a list and then create dropdownMenuItems. I am getting this error 'There should be exactly one item with [DropdownButton]'s value Either zero or 2 or more [DropdownMenuItem]s were detected with the same value'. I have look through similar solutions stating that the default value should be one of the values of the list which is not my case
Below is the list
const List<String> currenciesList = [
'AUD',
'BRL',
'CAD',
'CNY',
'EUR',
'GBP',
'HKD',
'IDR',
'ILS',
'INR',
'JPY',
'MXN',
'NOK',
'NZD',
'PLN',
'RON',
'RUB',
'SEK',
'SGD',
'USD',
'ZAR'
];
and the loop
String selectedCurrency = 'USD';
List<DropdownMenuItem<String>> dropdownItems = [];
List<DropdownMenuItem<String>> getDropDownItems() {
for (String currency in currenciesList) {
var newItem = DropdownMenuItem(
child: Text(currency),
value: currency,
);
dropdownItems.add(newItem);
}
return dropdownItems;
}
lastly the dropdownbutton
child: DropdownButton<String>(
value: selectedCurrency,
items: getDropDownItems(),
onChanged: (value) {
setState(() {
selectedCurrency = value!;
});
},
Please help me understand what i must have done wrong
Your code-snippet
DropdownButton<String>(
value: selectedCurrency,
items: getDropDownItems(), ///<= adding items on every state-build
onChanged: (value) {
setState(() {
selectedCurrency = value!;
});
},
On state changes means after you click on DropdownMenuItem you are calling again getDropDownItems(), in this case our it will add DropdownMenuItem again to dropdownItems, and so the DropdownButton having duplicate values, and you are getting errors.
Use initState to call it once, or just initialize the dropdownMenuItem.
Here is the Solution Widget
class _ItemSectionState extends State<ItemSection> {
List<DropdownMenuItem<String>> dropdownItems = []; //* you can make nullable if you want, I'm doing it to force having String.
String selectedCurrency = 'USD';
#override
void initState() {
super.initState();
dropdownItems = List.generate(
currenciesList.length,
(index) => DropdownMenuItem(
value: currenciesList[index],
child: Text(
currenciesList[index],
),
),
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
DropdownButton<String>(
items: dropdownItems,
value: selectedCurrency,
onChanged: (value) {
setState(() {
selectedCurrency = value!;
});
},
),
],
),
);
}
}
The error occurs due to duplicate values..
When you try to change the value of the drop down, the getDropDownItems function is rerun and the logic in there just duplicates the values for the dropdown.
a quick fix would be to simply map over the currenciesList as opposed to writing a function to add the widgets to a List as shown below:
String selectedCurrency = 'USD';
...
child: DropdownButton<String>(
value: selectedCurrency,
items: currenciesList.map((currency) => DropdownMenuItem(
child: Text(currency),
value: currency,
),
),
onChanged: (value) {
setState(() {
selectedCurrency = value!;
});
},
...
I've created a map of values to make checkboxes. The map consists of String and bools and when the value of the bool is changed, the check box value should change.
EDIT 1:
My ListView Checkbox
CheckboxListTile(
title: new Text(
key,
style: textHeaderStyle,
),
value: _selectedOrders.contains(undeliveryOrders[key]),
activeColor: Colors.pink,
checkColor: Colors.white,
onChanged: (bool value) {
setState(() {
if(value){
_selectedOrders.add(undeliveryOrders[key]);
undeliveryOrders[key] = value;
}else{
setState(() {
_selectedOrders.remove(undeliveryOrders[key]);
});
}
});
},
)
Creating the Map:
void _formatOrders(availableOrders) {
for (int i = 0; i < availableOrders.length; i++) {
var tempOrder = '${availableOrders[i].customer.uniqueInfo.name} , ${availableOrders[i].address}';
undeliveryOrders['$tempOrder'] = false;
}
print('$undeliveryOrders');
print('$numbers');
}
Selected Order Method
var _selectedOrders = [];
getItems() {
undeliveryOrders.forEach((key, value) {
if (value == false) {
_selectedOrders.add(key);
}
});
print(_selectedOrders);
_selectedOrders.clear();
}
I think you might be over complicating things every value does not have to be mapped to a boolean the way I do it is I add the value that gets checked to an array then check if that item is in that array if it is its true if not its false. You just have to remember to remove the item if the checkbox is unchecked here is some sample code for you.
List<String> items = ['Item 1', 'Item 2', 'Item 3'];
List<String> isChecked = [];
//Initialized outside build
ListView(
children: <Widget>[
...items
.map(
(item) => CheckboxListTile(
subtitle: Text('This is a subtitle'),
secondary: Text('This is Secondary text'),
title: Text(item),
value: isChecked.contains(item),
onChanged: (bool value) {
if (value) {
setState(() {
isChecked.add(item);
});
} else {
setState(() {
isChecked.remove(item);
});
}
},
),
)
.toList()
],
),
In my case, the setState() is not responding, try to use StatefulBuilder().
For Example:
...
bool isSelected = false;
StatefulBuilder(
builder: (context, _setState) {
return ListView(
children: [
CheckboxListTile(
value: isSelected,
onChanged: (bool? value) {
_setState(() => isSelected = value);
},
),
],
);
},
);
...
You can try with this code bellow ?
onChanged: (bool value) {
setState(() {
undeliveryOrders[key] = value ?? false;
});
},