for an authentication I would like to recover the base_url of the company chosen from a drop-down list, but I can't do it, being a beginner a little help will be welcome.
here is the code of the dropdownlist:
class DropDown extends StatefulWidget {
DropDown({Key key}) : super(key: key);
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<DropDown> {
String _mySelection;
String _myBaseUrl;
List<Map> _myJson = [{"id":2,"society":"test","baseUrl":"url.com"},{"id":1,"society":"planeef","baseUrl":"url.com"}];
#override
Widget build(BuildContext context) {
return Container(
child: new DropdownButton<String>(
isDense: true,
hint: new Text("Select"),
value: _mySelection,
onChanged: (String newValue) {
setState(() {
_mySelection = newValue;
});
},
items: _myJson.map((Map map) {
return new DropdownMenuItem<String>(
value: map["id"].toString(),
child: new Text(
map["society"],
),
);
}).toList(),
),
);
}
}
Check the code below. You can use singleWhere function to retrieve the element from the id value you are getting from the dropdown and then read baseUrl from the element.
The singleWhere function matches and returns a single element from the list based on the condition we provide.
Note -
The singleWhere function throws an error by default if there are duplicates or no element is found. You might need to also pass the orElse parameter to singleWhere or add some error handling in that case.
More about that can be found here.
class _MyHomePageState extends State<MyHomePage> {
String _mySelection;
List<Map> _myJson = [{"id":2,"society":"test","baseUrl":"url.com"},{"id":1,"society":"planeef","baseUrl":"url.com"}];
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: new DropdownButton<String>(
isDense: true,
hint: new Text("Select"),
value: _mySelection,
onChanged: (String newValue) {
Map<dynamic,dynamic> _myElement = _myJson.singleWhere((test) => test["id"] == int.parse(newValue));
print(_myElement["baseUrl"]);
//Add the above two lines
setState(() {
_mySelection = newValue;
});
},
items: _myJson.map((Map map) {
return new DropdownMenuItem<String>(
value: map["id"].toString(),
child: new Text(
map["society"],
),
);
}).toList(),
),
)
);
}
}
Related
TO SOLVE THIS U NEED TO RUN IT FIRST
Only for them who have experience with DropDownButton and T typepassing can solve this.
Please Help!
import 'package:flutter/material.dart';
// ignore: must_be_immutable
class SupDropDownButton<T> extends StatefulWidget {
FormFieldValidator<T>? validator;
ValueChanged<T> value;
final List<T> data;
SupDropDownButton(
{Key? key, required this.data, this.validator, required this.value})
: super(key: key);
#override
State<SupDropDownButton> createState() => _SupDropDownButtonState<T>();
}
class _SupDropDownButtonState<T> extends State<SupDropDownButton> {
T? _value;
List<DropdownMenuItem<T>> items() =>
widget.data.cast<T>().map<DropdownMenuItem<T>>(menuItem).toList();
DropdownMenuItem<T> menuItem(dynamic value) => DropdownMenuItem<T>(
value: value,
child: Text(value.name),
);
#override
Widget build(BuildContext context) {
return DropdownButtonFormField<T>(
decoration: const InputDecoration(border: InputBorder.none),
validator: widget.validator,
value: _value,
onChanged: (T? val) {
FocusScope.of(context).requestFocus(FocusNode());
_value = val!;
widget.value.call(val);
setState(() {});
},
items: items(),
hint: const Text('Please select Categories'),
);
}
}
THIS IS THE ERROR
Expected a value of type ((dynamic) => String?)?, but got one of type (Employee) => String?
I have worked on your code. Instead of value.name in your code, I have directly add List<String> for easy reference and it's working fine.I using null safety, that's why add late initialize to data list.if you need to create object and insert JSON data means revert back will rework on it
static data added like List<String> employeeList = ['hari','chetanPatil'] and cast it to data;
Working code :
// ignore: must_be_immutable
class SupDropDownButton<T> extends StatefulWidget {
FormFieldValidator<T>? validator;
ValueChanged<T> value;
late List<T> data;
SupDropDownButton(
{Key? key, required this.data, this.validator, required this.value})
: super(key: key);
#override
State<SupDropDownButton> createState() => _SupDropDownButtonState<T>();
}
class _SupDropDownButtonState<T> extends State<SupDropDownButton> {
T? _value;
List<String> employeeList = ['hari', 'chetanPatil'];
bool isOnLoad = true;
#override
void initState() {
super.initState();
}
List<DropdownMenuItem<T>> items() =>
widget.data.cast<T>().map<DropdownMenuItem<T>>(menuItem).toList();
DropdownMenuItem<T> menuItem(dynamic value) => DropdownMenuItem<T>(
value: value,
child: Text(value),
);
#override
Widget build(BuildContext context) {
widget.data.clear();
widget.data.addAll(employeeList);
return Scaffold(
body: Center(
child: Padding(
padding: const EdgeInsets.all(40.0),
child: DropdownButtonFormField<T>(
decoration: const InputDecoration(border: InputBorder.none),
validator: widget.validator,
value: _value,
onChanged: (T? val) {
FocusScope.of(context).requestFocus(FocusNode());
_value = val!;
print(_value);
widget.value.call(val);
setState(() {});
},
items: items(),
hint: const Text('Please select Categories'),
),
),
),
);
}
}
I want to autofill several textfields with one suggestion, like for example: If I select Washington as a state where I live I want the other field that would be country field to fill itself with U.S.
Thanks for your attention!
You will need to use setState( ) inside the onChanged. inside that setState, you will change the value of the other field otherDropdownValue . Here is a small example with dropDownMenus.
Dont forget you need a StatefulWidget (not StateLess)
Code:
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
String dropdownValue = 'One';
String otherDropdownValue = 'Two';
#override Widget build(BuildContext context) {
return Column(children: [
DropdownButton<String>(
value: dropdownValue,
onChanged: (String? newValue) {
//******************************************
//*****Here is what you are looking for*****
//******************************************
setState(() {
dropdownValue = newValue;
otherDropdownValue = newValue; ///Changes the other one
});
},
items: <String>['One', 'Two', 'Free', 'Four'].map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(value: value, child: Text(value),);}).toList(),
),
DropdownButton<String>(
value: otherDropdownValue,
onChanged: (String? newValue) {
setState(() {
otherDropdownValue = newValue;
});
},
items: <String>['One', 'Two', 'Free', 'Four'].map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(value: value, child: Text(value),);}).toList(),
),
],
);
}
}
Let me know if this does not help?
EDIT to answer your last comment:
Same logic to apply with a TextField or a textformfield.
You will need to add a TextEditingController() to control the text displayed.
Below is a fully working example (the part you need to look at is at the end)
and here is a link that explains the code (note I adjusted the code for your specific use case)
https://flutter.dev/docs/cookbook/forms/text-field-changes
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return const MaterialApp(
title: 'Retrieve Text Input',
home: MyCustomForm(),
);
}
}
// Define a custom Form widget.
class MyCustomForm extends StatefulWidget {
const MyCustomForm({Key? key}) : super(key: key);
#override
_MyCustomFormState createState() => _MyCustomFormState();
}
// Define a corresponding State class.
// This class holds data related to the Form.
class _MyCustomFormState extends State<MyCustomForm> {
// Create a text controller and use it to retrieve the current value
// of the TextField.
final myController = TextEditingController();
#override
void initState() {
super.initState();
// Start listening to changes.
myController.addListener(_printLatestValue);
}
#override
void dispose() {
// Clean up the controller when the widget is removed from the widget tree.
// This also removes the _printLatestValue listener.
myController.dispose();
super.dispose();
}
void _printLatestValue() {
print('Second text field: ${myController.text}');
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Retrieve Text Input'),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
///********************
///**** LOOK HERE ****
///********************
TextField(
onChanged: (text) {
myController.text = text;
},
),
TextField(
controller: myController,
),
],
),
),
);
}
}
I have this widget:
DropdownButton<String>(
value: rentPeriod,
items: rentPeriods.map((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(translate("expense.$value")),
);
}).toList(),
onChanged: (value) async {
setState(() {
rentPeriod = value;
});
},
),
How can I disable, let's say, the first option of the list?
i dont think there is any straight forward way of disabling a DropdownMenuItem
but you can have a list of the DropdownMenuItems you want to disable and then when you run setState you can check if that DropdownMenuItem is contained in that list and if it is then do nothing, also check by the DropdownMenuItem text if its contained in that list and if it is then change the color to be greyed out.
Like this
class MyWidget extends StatefulWidget {
#override
_MyWidgetState createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
var rentPeriods = <String>['one', 'two'];
final disabledItems = ['one'];
var rentPeriod;
#override
Widget build(BuildContext context) {
return DropdownButton<String>(
value: rentPeriod,
items: rentPeriods.map((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(
translate("expense.$value"),
style: TextStyle(
color: disabledItems.contains(value) ? Colors.grey : null,
),
),
);
}).toList(),
onChanged: (value) async {
if (!disabledItems.contains(value)) {
setState(() {
rentPeriod = value;
});
}
},
);
}
}
You can create your own disable customization, changing the color and the callback of onChangedfunction in the DropdownButton, like this example:
https://dartpad.dev/587b44d2f1b06e056197fcf705021699?null_safety=true
The problem was shown only after I added value to show the options in dropdown button.The image showed red screen instead of the app which said something about value should'nt be null
code was
import 'package:flutter/material.dart';
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
var _calculation = ["Sum ", "Subtraction", "Division", "Multiplication"];
var _currentItemselected = "Add";
#override
Widget build(BuildContext context) {
return Scaffold(
child: ListView(
children: <Widget>[
DropdownButton<String>(
items: _calculation.map((String dropdownStringItem) {
return DropdownMenuItem<String>(
value: dropdownStringItem,
child: Text(dropdownStringItem),
);
}).toList(),
onChanged: (String newValueSelected) {
setState(() {
this._currentItemselected = newValueSelected;
});
value:_currentItemselected;
},
},
The initial value of Of DropDownButton should be one of the items of list.
For example, add the value of _currentSelectedIndex to the list.
_calculation = ["Add", "Sum ", "Subtraction", "Division", "Multiplication"];
So I am struggling with the DropdownButtonFormField where when you change the value it runs the onChange function with the updated value. However, once the onChange finishes the value variable seems to reset itself meaning it never changes.
This is a cut-down version of the full form:
final _formKey = GlobalKey<FormState>();
TextEditingController assetGroupNameController = new TextEditingController();
TextEditingController assetGroupDescriptionController = new TextEditingController();
String assetGroupTypeController;
Widget build(BuildContext context) {
ProgressDialog pr;
assetGroupNameController.text = widget.assetGroup.name;
assetGroupDescriptionController.text = widget.assetGroup.description;
assetGroupTypeController = widget.assetGroup.type;
return ListView(
children: <Widget>[
Card(
elevation: 13.0,
child: Form(
key: _formKey,
child: DropdownButtonFormField(
value: assetGroupTypeController,
items: assetGroupTypes.map((f) {
return new DropdownMenuItem<String>(
value: f['key'],
child: new Text(f['text']),
);
}).toList(),
onChanged: (value) {
typeDropdownChange(value);
})
)
)
);
}
void typeDropdownChange(value) {
setState(() {
assetGroupTypeController = value;
});
}
You assigned the controller directly to value parameter of DropdownButtonFormField and you have string value for DropdownMenuItem. You should be storing the same data type value. Check below example and modify your code accordingly
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Material(
child: Center(
child: new MyDropDown(),
),
),
);
}
}
class MyDropDown extends StatefulWidget {
const MyDropDown({
Key key,
}) : super(key: key);
#override
_MyDropDownState createState() => _MyDropDownState();
}
class _MyDropDownState extends State<MyDropDown> {
String selected;
#override
Widget build(BuildContext context) {
return DropdownButtonFormField<String>(
value: selected,
items: ["Item 1", "Item 2", "Item 3"]
.map((label) => DropdownMenuItem<String>(
child: Text(label),
value: label,
))
.toList(),
onChanged: (value) {
setState(() => selected = value);
},
);
}
}