I have a list of reasons stored in my form controller using GetX
class formController extends GetxController {
String rejectreason1 = "Overheat";
List reasons = [
"Broken",
"Missing",
"Wet Wiring",
"Overheat",
"Orange",
"Obergene"
];
Widget Class:
class ReasonForm extends StatelessWidget {
formController formC = Get.put(formController());
ReasonForm(this.index, {Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
// TODO: implement build
return Form(
// key: formKey1,
child: Column(children: [
DropdownButtonFormField<String>(
decoration: const InputDecoration(icon: Icon(Icons.event)),
value: "Overheat",
icon: const Icon(Icons.arrow_downward),
style: const TextStyle(color: Colors.deepPurple),
items: formC.reasons.map((value) {
return DropdownMenuItem(
value: value.toString(),
child: Text(value),
);
}).toList(),
onChanged: (value) {
formC.rejectreason1 = value!;
print("Selected ${value}");
},
),
]),
);
}
}
and in the dropdown list with it being mapped when onChanged is called all the values can be stored and printed out but for some reason the item "Overheat" doesn't work. Other words such as "Others" also doesn't work either, but all the rest like orange, missing and others can be selected and printed out in the console.
I think its because you put value: "Overheat", so you can't change it because onTap function change formC.rejectreason1 but you dont put that value on your dropdown. Try to change it to value: formC.rejectreason1
Related
Need to pass dropdown selected value from OrderListScreen to firebase collection order. Dont know the proper
way of passing this field value to be reflect in firebase. Code for dropdown is ok
need to get that selected value to be able to pass it to orderStatus field. Please help.
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/src/foundation/key.dart';
import 'package:flutter/src/widgets/framework.dart';
class OrderListScreen extends StatefulWidget {
const OrderListScreen({Key? key}) : super(key: key);
#override
State<OrderListScreen> createState() => _OrderListScreenState();
}
class _OrderListScreenState extends State<OrderListScreen> {
String? newvalue;
#override
Widget build(BuildContext context) {
String dropdownvalue = 'Pending';
return Material(
child: Container(
child: Column(
children: <Widget>[
Text(" Please select the order status from the dropdown Below:",
style: TextStyle(backgroundColor: Colors.orange)),
Container(
child: Material(
child: DropdownButton<String>(
value: newvalue,
items: <String>[
'Pending',
'Confirmed',
'Dispatched',
'Received'
].map((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
onChanged: (String? newvalue) {
setState(() {
this.newvalue = newvalue;
});
},
),
)),
],
),
),
);
}
}
This question has already been answered in this thread
on select something from dropdown the value will be stored in dropdownValue
then to store to firebase
FirebaseFirestore.instance
.collection("collection")
.doc(result.user.uid)
.set({
'Name': _Name.text,
'myDropdownValue":dropdownValue
});
I'm new to Flutter and I'm working on a localization feature using the easy_localizations package. I created a dropdown that shows languages you can switch to and it works perfectly fine when the dropdown is directly on the page. But since it will be on every page, I want to have the dropdown as a custom widget instead, and then just import it on the pages, like this:
const Padding(
padding: xPadding25,
child: DropDown(),
),
However, that does not work. I'm still able to click on the dropdown and choose a language, but it doesn't translate the pages anymore. I think it has to do something with the context it's translating, but I don't know how to make it so that it will take context of the pages and not its own if it makes sense.
Here's the code for the DropDown widget:
class DropDown extends StatefulWidget {
const DropDown({Key? key}) : super(key: key);
#override
State<DropDown> createState() => _DropDownState();
}
String dropdownValue = 'English';
class _DropDownState extends State<DropDown> {
#override
Widget build(BuildContext context) {
return (DropdownButton<String>(
icon: const Icon(
Icons.language,
color: scTealColor,
),
value: dropdownValue,
elevation: 16,
style: smBodyStyle,
underline: Container(
height: 2,
color: scTealColor,
),
onChanged: (String? newValue) {
setState(() {
dropdownValue = newValue ?? "";
if (dropdownValue == 'French') {
context.setLocale(const Locale('fr'));
} else {
context.setLocale(const Locale('en'));
}
});
},
items: <String>['English', 'French']
.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
));
}
}
Any ideas on how to implement it so that the translation works when imported to pages as a custom widget? Thanks!
Have you tried to pass context into your dropdown class ? for i.e.,
const Padding(
padding: xPadding25,
child: DropDown(context),
),
I am getting this error in the console when I am trying to use flutter DropdownButton Widget.
package:flutter/src/material/dropdown.dart': Failed assertion: line 1252 pos 12: 'widget.items!.where((DropdownMenuItem item) => item.value == widget.value).length == 1': is not true.
There is a long traceback...
Here I am adding small code sample that will reproduce this error... Anyone can simply copy paste in main.dart file
// flutter import
import 'package:flutter/material.dart';
void main() {
runApp(const BugReportApp());
}
class BugReportApp extends StatefulWidget {
const BugReportApp({Key? key}) : super(key: key);
#override
State<BugReportApp> createState() => _BugReportAppState();
}
class _BugReportAppState extends State<BugReportApp> {
final TextEditingController _dropdownController = TextEditingController();
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Bug Report',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Flex(direction: Axis.vertical, children:[
DropdownButton<String>(
value: _dropdownController.text == ""
? null
: _dropdownController.text,
items: ["hello, world", "how are you", "goodbye"]
.map((_value) => DropdownMenuItem<String>(
child: Text(
_value,
)))
.toList(),
onChanged: (_value) {
setState(() {
_dropdownController.text = _value ?? _dropdownController.text;
});
},
),
],),
);
}
}
I was expecting dropown to work normally but, I don't know why it didn't.
You are missing value on DropdownMenuItem.
.map((_value) => DropdownMenuItem<String>(
value: _value, // this
child: Text(
_value,
)))
Also make sure to use Scaffold on home.
Try this code, also added some explanation in the code:
class _MyHomePageState extends State<MyHomePage> {
final TextEditingController _dropdownController = TextEditingController();
String? dropDownValue = 'hello, world'; // add one value as the defaul one which must exists in the dropdown value
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: Column(
children: [
Flex(direction: Axis.vertical, children:[
DropdownButton<String>(
value: dropDownValue, // this place should not have a controller but a variable
onChanged: (_value) {
setState(() {
dropDownValue = _value;
});
},
items: ["hello, world", "how are you", "goodbye"]
.map<DropdownMenuItem<String>>((String _value) => DropdownMenuItem<String>(
value: _value, // add this property an pass the _value to it
child: Text(_value,)
)).toList(),
),
])
],
),
);
}
}
please add the VALUE field in both DropdownMenuItem and DropdownButton to prevent error
I have a fairly complex form where the drop down list changes based on previous selections. For example, if I select option Delivery or Pickup, the next drop down would be based on that selection and show either a store list or delivery options.
I have the below code and have a tried a few options, but the drop down doesn't seem to update based on selection, however I can't figure out why as it should be refreshed with the state change.
Any suggestion on the best approach for this? I thought it might be related to the Key needing to be unique but that doesn't seem to solve the problem and also causes other issues like clear of selected item when other fields change.
Question: How can you provide dynamic drop downs based on previous form field selection in Dart/Flutter?
DropDownInputField(
inputList: const [
'Delivery',
'Pickup',
],
onchanged: (selection) {
setState(() {
order.shippingOption = selection;
});
},
name: 'Shipping Option',
),
const SizedBox(
height: 20,
),
DropDownInputField(
inputList: retrieveList(order.shippingOption),
onchanged: (value) => order.deliveryOption = value,
name: 'Delivery Options',
),
Option generation Function
List<String> retrieveList(String shippingOption) {
switch (shippingOption.toLowerCase()) {
case "delivery":
return [
'Standard',
'Express',
];
break;
case "pickup":
return [
'Store 1',
'Store 2',
];
break;
State Class
class _ShippingFormScreenState extends State<ShippingFormScreen>
with SingleTickerProviderStateMixin {
TabController tabController;
Order order;
generation Function will decide the second dropdown items. But 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.
On First DropDownFiled onChanged make seceond dropdown value null.
DropDownInputField(
inputList: const [
'Delivery',
'Pickup',
],
onchanged: (selection) {
setState(() {
order.shippingOption = selection;
order.deliveryOption = null;
});
},
name: 'Shipping Option',
),
And second dropdown seems ok . But make sure to make those field as nullable.
I will encourage you to check this
You have to disable the bottom drop down based on top drop down using onChanged
From the documentation, Disabling like this:
If items or onChanged is null, the button will be disabled, the down arrow will be grayed out, and the disabledHint will be shown (if provided)
So we will disable bottom drop down and see if order changes.
You should change bottom drop down onChanged function to this
items: retrieveList(order.shippingOption),
onChanged: order.shippingOption == null
? null
: (value) {
setState(() {
order.deliveryOption = value!;
});
},
and change retrieveList to this:
List<String> retrieveList(String? shippingOption) {
if (shippingOption == null) return [];
switch (shippingOption.toLowerCase()) {
case "delivery":
return [
'Standard',
'Express',
];
case "pickup":
return [
'Store 1',
'Store 2',
];
default:
throw Exception('Unknown shipping option');
}
}
}
Full code of the widget
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
Order order = Order();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
DropDownInputField(
items: const [
'Delivery',
'Pickup',
],
onChanged: (value) {
setState(() {
order.shippingOption = value!;
});
},
value: order.shippingOption,
name: 'Shipping Option',
),
const SizedBox(
height: 20,
),
DropDownInputField(
items: retrieveList(order.shippingOption),
onChanged: order.shippingOption == null
? null
: (value) {
setState(() {
order.deliveryOption = value!;
});
},
name: 'Delivery Options',
value: order.deliveryOption,
),
],
),
),
);
}
List<String> retrieveList(String? shippingOption) {
if (shippingOption == null) return [];
switch (shippingOption.toLowerCase()) {
case "delivery":
return [
'Standard',
'Express',
];
case "pickup":
return [
'Store 1',
'Store 2',
];
default:
throw Exception('Unknown shipping option');
}
}
}
class Order {
String? shippingOption;
String? deliveryOption;
}
class DropDownInputField extends StatelessWidget {
const DropDownInputField({
Key? key,
required this.items,
required this.onChanged,
required this.value,
required this.name,
}) : super(key: key);
final List<String> items;
final ValueChanged<String?>? onChanged;
final String? value;
final String name;
#override
Widget build(BuildContext context) {
return DropdownButton<String>(
value: value,
hint: Text(name),
items: <DropdownMenuItem<String>>[
...items.map((e) => DropdownMenuItem(
child: Text(e),
value: e,
))
],
onChanged: onChanged,
);
}
}
For a DropDown when I select any purticular option that value gets displayed in the dropDown.
How do I effectively change what is displayed once a purticular drop down menu item is clicked on.
As you can see from the below images. In the Brands Dropdown once I select an item its value gets displayed. However, I would like to change the value that is displayed.
How do I accomplish that? Thanks.
EDITED please pay attention on hint property and this.hintValue
You need to set State in onChanged event and associate value to new value grabbed from onchanged like this
onChanged: (String newValue) {
setState(() {
this.hintValue = newValue;
});
},
while:
return DropdownButton<String>(
value: dropdownValue,
hint: Text("${this.hintValue}"),
icon: Icon(Icons.arrow_downward),
iconSize: 24,
fullcode will be like this:
class DropDownWidget extends StatefulWidget {
DropDownWidget({Key key}) : super(key: key);
#override
_DropDownWidgetState createState() => _DropDownWidgetState();
}
/// This is the private State class that goes with MyStatefulWidget.
class _DropDownWidgetState extends State<DropDownWidget> {
String dropdownValue = 'One';
String hintValue;
#override
Widget build(BuildContext context) {
return DropdownButton<String>(
value: dropdownValue,
hint: Text("${this.hintValue}"),
icon: Icon(Icons.arrow_downward),
iconSize: 24,
elevation: 16,
style: TextStyle(color: Colors.deepPurple),
underline: Container(
height: 2,
color: Colors.deepPurpleAccent,
),
onChanged: (String newValue) {
setState(() {
this.hintValue = newValue;
});
},
items: <String>['One', 'Two', 'Free', 'Four']
.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
);
}
}
reference from: flutter docs