Related
I have a radio buttons created but while on click of the buttons the value is not getting changed.
here is my code.
Widget _buildOmsIDTextField() {
// Group Value for Radio Button.
int id = 1;
List<OptionList> nList = [
OptionList(
padding : const EdgeInsets.fromLTRB(14.0, 180, 25, 50),
index: 1,
option: "Accept",
),
OptionList(
padding : const EdgeInsets.all(14.0),
index: 2,
option: "Reject",
),
];
return Column(
children: <Widget>[
const Padding(
padding : EdgeInsets.all(14.0),
child: Text("Please Select an Option", style: TextStyle(fontSize: 23))
),
SizedBox(
height: 150.0,
child: Column(
children:
nList.map((data) => RadioListTile(
title: Text(data.option),
groupValue: data.index,
value: id,
onChanged: (val) {
setState(() {
radioItemHolder = data.option ;
id = data.index;
});
},
)).toList(),
),
),
],
);
}
Any help would be highly appreciated!
While you are calling _buildOmsIDTextField() inside build method, the int id = 1; will always get 1. Put your group value outside the build method. And use same group value on radio buttons.
// Group Value for Radio Button. I also prefer putting any decleared varable for radio button here
int id = 1;
Widget _buildOmsIDTextField() {...
...
nList.map((data) => RadioListTile(
title: Text(data.option),
groupValue: id,
value: data.option,
}
#override
Widget build(BuildContext context) {
A better way of doing this, providing data type on RadioListTile.
OptionList? selectOption;
List<OptionList> nList = [
OptionList(
padding: const EdgeInsets.fromLTRB(14.0, 180, 25, 50),
index: 1,
option: "Accept",
),
OptionList(
padding: const EdgeInsets.all(14.0),
index: 2,
option: "Reject",
),
];
Widget _buildOmsIDTextField() {
return Column(
children: <Widget>[
const Padding(
padding: EdgeInsets.all(14.0),
child: Text("Please Select an Option",
style: TextStyle(fontSize: 23))),
SizedBox(
height: 150.0,
child: Column(
children: nList
.map((data) => RadioListTile<OptionList>(
title: Text(data.option),
groupValue: selectOption,
value: data,
onChanged: (val) {
setState(() {
selectOption = val;
});
},
))
.toList(),
),
),
],
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: _buildOmsIDTextField(),
);
}
I am trying to develop a survey form using Flutter and I have multiple dropdown fields in the form. I want to get the selected values from those dropdowns when I click the save button. But all I am getting is the value I initially set inside initState(). The code I am using is as below. Any help to get this sorted out is much appreciated.
class _EditSurveyState extends State<EditSurvey> {
String contactMethod;
String country;
List contactMethodList = ['phone', 'email', 'mail'];
List countryList = ['us', 'uk', 'germany'];
#override
void initState() {
super.initState();
contactMethod = surveryData['contact'];
country = surveryData['country'];
}
#override
Widget build(BuildContext context) {
return Scaffold(
return Scaffold(
children: [
Expanded(
flex: screenWidth(context) < 1300 ? 10 : 8,
child: SafeArea(
child: Column(
children: [
createDropdownField("Contact", contactMethod, contactMethodList),
createDropdownField("Country", country, countryList),
Row(mainAxisAlignment: MainAxisAlignment.end,
children: [
ElevatedButton(
onPressed: () async {
print(contactMethod + country);
},
style: ElevatedButton.styleFrom(
padding: EdgeInsets.symmetric(horizontal: 50),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10)
)
),
child: Text(
"UPDATE",
style: TextStyle(
color: Colors.white,
fontSize: 15.0,
fontWeight: FontWeight.bold,
),
)
),
],
),
]
)
)
)
]
)
);
}
Row createDropdownField(String labelText, String _valueChoose, List valueList) {
return Row (
children: [
SizedBox(height: 25,),
Align(
alignment: Alignment.centerLeft,
child: Text(
'$labelText',
),
),
DropdownButtonFormField(
value: _valueChoose,
hint: Text("$labelText"),
icon: Icon(Icons.arrow_drop_down),
isExpanded: true,
onChanged: (newValue){
setState(() {
_valueChoose = newValue;
});
},
items: valueList.map((valueItem){
return DropdownMenuItem(
value: valueItem,
child: Text(valueItem),
);
}).toList(),
),
],
);
}
}
I don't understand why you using intitstate if you want to initialize value to String you can do it while declaring, try removing initstate and
Declare a variable first where you will store new value from dropdown onchange
i.e
class _EditSurveyState extends State<EditSurvey> {
String _currentValue;
DropdownButtonFormField(
onChanged: (val) =>
setState(() => _currentValue = val as String),
value: _currentValue ,
items: YourList.map((item) {
return DropdownMenuItem(
value: item,
child: Text('$item Items'),
);
}).toList(),
),
I have a form (second screen) which is used for CRUD. When i add data, it is saved to list view as you can see on the table.
The list view is passed to (first screen) where i can iterate and see the list data with updated content.
However, when i click on go to second screen, the list view data disappears. The given 3 lists are hard coded for testing purpose.
Now, my question is that, How can i keep the data in the table and not disappear, even if i change screen back and forth multiple times. My code is as below: -
**
Main.dart File
**
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String _userInformation = 'No information yet';
void languageInformation() async {
final language = await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Episode5(),
),
);
updateLanguageInformation(language);
}
void updateLanguageInformation(List<User> userList) {
for (var i = 0; i <= userList.length; i++) {
for (var name in userList) {
print("Name: " + name.name[i] + " Email: " + name.email[i]);
}
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Testing List View Data From second page to first page"),
),
body: Column(
children: <Widget>[
Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Text(_userInformation),
],
),
SizedBox(
height: 10.0,
),
ElevatedButton(
onPressed: () {
languageInformation();
},
child: Text("Go to Form"),
),
],
),
);
}
}
2. Model.dart File:
class User {
String name;
String email;
User({this.name, this.email});
}
3. Episode5 File
class Episode5 extends StatefulWidget {
#override
_Episode5State createState() => _Episode5State();
}
class _Episode5State extends State<Episode5> {
TextEditingController nameController = TextEditingController();
TextEditingController emailController = TextEditingController();
final form = GlobalKey<FormState>();
static var _focusNode = new FocusNode();
bool update = false;
int currentIndex = 0;
List<User> userList = [
User(name: "a", email: "a"),
User(name: "d", email: "b"),
User(name: "c", email: "c"),
];
#override
Widget build(BuildContext context) {
Widget bodyData() => DataTable(
onSelectAll: (b) {},
sortColumnIndex: 0,
sortAscending: true,
columns: <DataColumn>[
DataColumn(label: Text("Name"), tooltip: "To Display name"),
DataColumn(label: Text("Email"), tooltip: "To Display Email"),
DataColumn(label: Text("Update"), tooltip: "Update data"),
],
rows: userList
.map(
(user) => DataRow(
cells: [
DataCell(
Text(user.name),
),
DataCell(
Text(user.email),
),
DataCell(
IconButton(
onPressed: () {
currentIndex = userList.indexOf(user);
_updateTextControllers(user); // new function here
},
icon: Icon(
Icons.edit,
color: Colors.black,
),
),
),
],
),
)
.toList(),
);
return Scaffold(
appBar: AppBar(
title: Text("Data add to List Table using Form"),
),
body: Container(
child: Column(
children: <Widget>[
bodyData(),
Padding(
padding: EdgeInsets.all(10.0),
child: Form(
key: form,
child: Container(
child: Column(
children: <Widget>[
TextFormField(
controller: nameController,
focusNode: _focusNode,
keyboardType: TextInputType.text,
autocorrect: false,
maxLines: 1,
validator: (value) {
if (value.isEmpty) {
return 'This field is required';
}
return null;
},
decoration: new InputDecoration(
labelText: 'Name',
hintText: 'Name',
labelStyle: new TextStyle(
decorationStyle: TextDecorationStyle.solid),
),
),
SizedBox(
height: 10,
),
TextFormField(
controller: emailController,
keyboardType: TextInputType.text,
autocorrect: false,
maxLines: 1,
validator: (value) {
if (value.isEmpty) {
return 'This field is required';
}
return null;
},
decoration: new InputDecoration(
labelText: 'Email',
hintText: 'Email',
labelStyle: new TextStyle(
decorationStyle: TextDecorationStyle.solid)),
),
SizedBox(
height: 10,
),
Column(
children: <Widget>[
Center(
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
TextButton(
child: Text("Add"),
onPressed: () {
form.currentState.save();
addUserToList(
nameController.text,
emailController.text,
);
},
),
TextButton(
child: Text("Update"),
onPressed: () {
form.currentState.save();
updateForm();
},
),
],
),
Row(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
ElevatedButton(
child: Text("Save and Exit"),
onPressed: () {
form.currentState.save();
addUserToList(
nameController.text,
emailController.text,
);
Navigator.pop(context, userList);
},
),
],
),
],
),
),
],
),
],
),
),
),
),
],
),
),
);
}
void updateForm() {
setState(() {
User user = User(name: nameController.text, email: emailController.text);
userList[currentIndex] = user;
});
}
void _updateTextControllers(User user) {
setState(() {
nameController.text = user.name;
emailController.text = user.email;
});
}
void addUserToList(name, email) {
setState(() {
userList.add(User(name: name, email: email));
});
}
}
So instead of passing data back and forth between pages, its better to implement a state management solution so that you can access your data from anywhere in the app, without having to manually pass anything.
It can be done with any state management solution, here's how you could do it with GetX.
I took all your variables and methods and put them in a Getx class. Anything in this class will be accessible from anywhere in the app. I got rid of setState because that's no longer how things will be updated.
class FormController extends GetxController {
TextEditingController nameController = TextEditingController();
TextEditingController emailController = TextEditingController();
int currentIndex = 0;
List<User> userList = [
User(name: "a", email: "a"),
User(name: "d", email: "b"),
User(name: "c", email: "c"),
];
void updateForm() {
User user = User(name: nameController.text, email: emailController.text);
userList[currentIndex] = user;
update();
}
void updateTextControllers(User user) {
nameController.text = user.name;
emailController.text = user.email;
update();
}
void addUserToList(name, email) {
userList.add(User(name: name, email: email));
update();
}
void updateLanguageInformation() {
// for (var i = 0; i <= userList.length; i++) { // ** don't need nested for loop here **
for (var user in userList) {
print("Name: " + user.name + " Email: " + user.email);
}
// }
}
}
GetX controller can be initialized anywhere before you try to use it, but lets do it main.
void main() {
Get.put(FormController()); // controller init
runApp(MyApp());
}
Here's your page, we find the controller and now all variables and methods come from that controller.
class Episode5 extends StatefulWidget {
#override
_Episode5State createState() => _Episode5State();
}
class _Episode5State extends State<Episode5> {
final form = GlobalKey<FormState>();
static var _focusNode = new FocusNode();
// finding same instance if initialized controller
final controller = Get.find<FormController>();
#override
Widget build(BuildContext context) {
Widget bodyData() => DataTable(
onSelectAll: (b) {},
sortColumnIndex: 0,
sortAscending: true,
columns: <DataColumn>[
DataColumn(label: Text("Name"), tooltip: "To Display name"),
DataColumn(label: Text("Email"), tooltip: "To Display Email"),
DataColumn(label: Text("Update"), tooltip: "Update data"),
],
rows: controller.userList // accessing list from Getx controller
.map(
(user) => DataRow(
cells: [
DataCell(
Text(user.name),
),
DataCell(
Text(user.email),
),
DataCell(
IconButton(
onPressed: () {
controller.currentIndex =
controller.userList.indexOf(user);
controller.updateTextControllers(user);
},
icon: Icon(
Icons.edit,
color: Colors.black,
),
),
),
],
),
)
.toList(),
);
return Scaffold(
appBar: AppBar(
title: Text("Data add to List Table using Form"),
),
body: Container(
child: Column(
children: <Widget>[
// GetBuilder rebuilds when update() is called
GetBuilder<FormController>(
builder: (controller) => bodyData(),
),
Padding(
padding: EdgeInsets.all(10.0),
child: Form(
key: form,
child: Container(
child: Column(
children: <Widget>[
TextFormField(
controller: controller.nameController,
focusNode: _focusNode,
keyboardType: TextInputType.text,
autocorrect: false,
maxLines: 1,
validator: (value) {
if (value.isEmpty) {
return 'This field is required';
}
return null;
},
decoration: InputDecoration(
labelText: 'Name',
hintText: 'Name',
labelStyle: new TextStyle(
decorationStyle: TextDecorationStyle.solid),
),
),
SizedBox(
height: 10,
),
TextFormField(
controller: controller.emailController,
keyboardType: TextInputType.text,
autocorrect: false,
maxLines: 1,
validator: (value) {
if (value.isEmpty) {
return 'This field is required';
}
return null;
},
decoration: InputDecoration(
labelText: 'Email',
hintText: 'Email',
labelStyle: new TextStyle(
decorationStyle: TextDecorationStyle.solid)),
),
SizedBox(
height: 10,
),
Column(
children: <Widget>[
Center(
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
TextButton(
child: Text("Add"),
onPressed: () {
form.currentState.save();
controller.addUserToList(
controller.nameController.text,
controller.emailController.text,
);
},
),
TextButton(
child: Text("Update"),
onPressed: () {
form.currentState.save();
controller.updateForm();
},
),
],
),
Row(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
ElevatedButton(
child: Text("Save and Exit"),
onPressed: () {
form.currentState.save();
controller.updateLanguageInformation(); // all this function does is print the list
Navigator.pop(
context); // don't need to pass anything here
},
),
],
),
],
),
),
],
),
],
),
),
),
),
],
),
),
);
}
}
And here's your other page. I just threw in a ListView.builder wrapped in a GetBuilder<FormController> for demo purposes. It can now be stateless.
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Testing List View Data From second page to first page"),
),
body: Column(
children: <Widget>[
Expanded(
child: GetBuilder<FormController>(
builder: (controller) => ListView.builder(
itemCount: controller.userList.length,
itemBuilder: (context, index) => Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Text(controller.userList[index].name),
Text(controller.userList[index].email),
],
),
),
),
),
SizedBox(
height: 10.0,
),
ElevatedButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Episode5(),
),
);
},
child: Text("Go to Form"),
),
],
),
);
}
}
As your app expands you can create more controller classes and they're all very easily accessible from anywhere. Its a way easier and cleaner way to do things than manually passing data around everywhere.
I have a page that consists of a ListView, which contains TextFormFields. The user can add or remove items from that ListView.
I use the bloc pattern, and bind the number of Items and their content inside the ListView to a list saved in the bloc state. When I want to remove the items, I remove the corresponding text from this list and yield the new state. However, this will always remove the last item, instead of the item that's supposed to be removed. While debugging, I can clearly see that the Item I want removed is in fact removed from the state's list. Still, the ListView removes the last item instead.
I've read that using keys solves this problem and it does. However, if I use keys there is a new problem.
Now, the TextFormField will go out of focus every time a character is written. I guess this is to do with the fact that the ListView is redrawing its items everytime a character is typed, and somehow having a key makes the focus behave differently.
Any ideas how to solve this?
The page code (The ListView is at the bottom):
class GiveBeneftis extends StatelessWidget {
#override
Widget build(BuildContext context) {
var bloc = BlocProvider.of<CreateChallengeBloc>(context);
return BlocBuilder<CreateChallengeBloc, CreateChallengeState>(
builder: (context, state) {
return CreatePageTemplate(
progress: state.progressOfCreation,
buttonBar: NavigationButtons(
onPressPrevious: () {
bloc.add(ProgressOfCreationChanged(nav_direction: -1));
Navigator.of(context).pop();
},
onPressNext: () {
bloc.add(ProgressOfCreationChanged(nav_direction: 1));
Navigator.of(context).pushNamed("create_challenge/add_pictures");
},
previous: 'Details',
next: 'Picture',
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Text(
'List the benefits of you Challenge',
textAlign: TextAlign.center,
style: TextStyle(fontSize: 28, fontWeight: FontWeight.bold),
),
SizedBox(height: 30),
Text(
'Optionally: Make a list of physical and mental benefits the participants can expect. ',
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.grey,
fontSize: 14,
fontWeight: FontWeight.w400),
),
SizedBox(height: 50),
Container(
margin: EdgeInsets.all(8.0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
color: Colors.yellow[600]),
child: FlatButton(
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
onPressed: () => bloc.add(ChallengeBenefitAdded()),
child: Text('Add a benefit',
style: TextStyle(
color: Colors.white, fontWeight: FontWeight.bold)),
),
),
Expanded(
child: new ListView.builder(
itemCount: state.benefits.length,
itemBuilder: (BuildContext context, int i) {
final item = state.benefits[i];
return Padding(
padding: EdgeInsets.symmetric(horizontal: 25),
child: TextFieldTile(
//key: UniqueKey(),
labelText: 'Benefit ${i + 1}',
validator: null,
initialText: state.benefits[i],
onTextChanged: (value) => bloc.add(
ChallengeBenefitChanged(
number: i, text: value)),
onCancelIconClicked: () {
bloc.add(ChallengeBenefitRemoved(number: i));
},
));
})),
],
),
);
});
}
}
The Code of the TextfieldTile:
class TextFieldTile extends StatelessWidget {
final Function onTextChanged;
final Function onCancelIconClicked;
final Function validator;
final String labelText;
final String initialText;
const TextFieldTile(
{Key key,
this.onTextChanged,
this.onCancelIconClicked,
this.labelText,
this.initialText,
this.validator})
: super(key: key);
#override
Widget build(BuildContext context) {
return Stack(children: <Widget>[
TextFormField(
textCapitalization: TextCapitalization.sentences,
initialValue: initialText,
validator: validator,
onChanged: onTextChanged,
maxLines: null,
decoration: InputDecoration(
labelText: labelText,
)),
Align(
alignment: Alignment.topRight,
child: IconButton(
icon: Icon(Icons.cancel), onPressed: onCancelIconClicked),
),
]);
}
}
The relevant portion of the Bloc:
if (event is ChallengeBenefitAdded) {
var newBenefitsList = List<String>.from(state.benefits);
newBenefitsList.add("");
yield state.copyWith(benefits: newBenefitsList);
}
else if (event is ChallengeBenefitChanged) {
var newBenefitsList = List<String>.from(state.benefits);
newBenefitsList[event.number] = event.text;
yield state.copyWith(benefits: newBenefitsList);
}
else if (event is ChallengeBenefitRemoved) {
var newBenefitsList = List<String>.from(state.benefits);
newBenefitsList.removeAt(event.number);
yield state.copyWith(benefits: newBenefitsList);
}
I can think of two things you can do here.
Create a different bloc for processing the changes in the text field, that will avoid having to actually update the state of the entire list if no needed.
Have a conditional to avoid rebuilding the list when your bloc change to a state that is relevant only to the keyboard actions.
Example:
BlocBuilder<CreateChallengeBloc, CreateChallengeState>(
buildWhen: (previousState, currentState) {
return (currentState is YourNonKeyboardStates);
}
...
);
I have a dropdown button which works fine, but when I try to set a default value it will fail with the following error:
'package:flutter/src/material/dropdown.dart': Failed assertion: line 620 pos 15: 'items == null || items.isEmpty || value == null || items.where((DropdownMenuItem item) => item.value == value).length == 1': is not true.
This is my dropdown button:
Widget changeWorkspace() {
return StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return Column(mainAxisSize: MainAxisSize.min, children: <Widget>[
Padding(
padding: EdgeInsets.all(8.0),
child: DropdownButton<AssignedWorkspace>(
isExpanded: true,
hint: Text("SELECT WORKSPACE"),
value: selectedWorkspace,
onChanged: (dropdownValueSelected) {
setState(() {
selectedWorkspace = dropdownValueSelected;
});
},
items: workspaces != null && workspaces.length > 0
? workspaces.map((AssignedWorkspace workspace) {
return new DropdownMenuItem<AssignedWorkspace>(
value: workspace,
child: new Text(workspace.name,
style: new TextStyle(color: Colors.black)),
);
}).toList()
: null),
),
]);
});
}
I've tried to set the value of selectedWorkspace onInit as follows but it fails.
selectedWorkspace = new AssignedWorkspace(
id: userSettings.currentWorkspaceId,
name: userSettings.currentWorkspaceName);
Is there a way of setting a default value in a dropdown button?
import 'package:flutter/material.dart';
import '../config/app_theme.dart';
class DropdownWidget extends StatefulWidget {
final String title;
final List<String> items;
final ValueChanged<String> itemCallBack;
final String currentItem;
final String hintText;
DropdownWidget({
this.title,
this.items,
this.itemCallBack,
this.currentItem,
this.hintText,
});
#override
State<StatefulWidget> createState() => _DropdownState(currentItem);
}
class _DropdownState extends State<DropdownWidget> {
List<DropdownMenuItem<String>> dropDownItems = [];
String currentItem;
AppTheme appTheme;
_DropdownState(this.currentItem);
#override
void initState() {
super.initState();
for (String item in widget.items) {
dropDownItems.add(DropdownMenuItem(
value: item,
child: Text(
item,
style: TextStyle(
fontSize: 16,
),
),
));
}
}
#override
void didUpdateWidget(DropdownWidget oldWidget) {
if (this.currentItem != widget.currentItem) {
setState(() {
this.currentItem = widget.currentItem;
});
}
super.didUpdateWidget(oldWidget);
}
#override
Widget build(BuildContext context) {
appTheme = AppTheme(Theme.of(context).brightness);
return Container(
margin: EdgeInsets.symmetric(vertical: 10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Container(
margin: EdgeInsets.only(left: 6),
child: Text(
widget.title,
style: appTheme.activityAddPageTextStyle,
),
),
Container(
padding: EdgeInsets.symmetric(vertical: 3, horizontal: 15),
margin: EdgeInsets.only(top: 10),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(6),
color: Colors.white,
boxShadow: [
BoxShadow(
offset: Offset(0, 2),
blurRadius: 10,
color: Color(0x19000000),
),
],
),
child: DropdownButtonHideUnderline(
child: DropdownButton(
icon: appTheme.activityAddPageDownArrowSVG,
value: currentItem,
isExpanded: true,
items: dropDownItems,
onChanged: (selectedItem) => setState(() {
currentItem = selectedItem;
widget.itemCallBack(currentItem);
}),
hint: Container(
child: Text(widget.hintText, style: appTheme.hintStyle),
),
),
),
),
],
),
);
}
}
This is my dropDownWidget without optimization. It has currentItem. You could use it like:
DropdownWidget(
title: kStatus,
items: state.customerStepInfo.statusList,
currentItem: status,
hintText: kCommonPick,
itemCallBack: (String status) {
this.status = status;
},
)
You need implement "equals" in class AssignedWorkspace. I used equatable package.
Example class AssignedWorkspace
class AssignedWorkspace extends Equatable {
final String id;
final String name;
AssignedWorkspace(this.id, this.name);
#override
List<Object> get props => [id];
}
For me id of one of the element is null, once added id is made non-null issue got fixed.
I changed the value of the dropdown var to 1 initially
var _value = '1';
So when the dropdown button has to display its value it displays the one whose value I have set 1 as in the items list in DropDownButton
DropdownButton(
underline: Container(),
onChanged: (value) {
setState(() {
_value = value;
});
},
value: _value,
items: [
DropdownMenuItem(
value: "1",
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Icon(MaterialCommunityIcons.devices),
SizedBox(width: 10),
Text(
"Consumption",
style: TextStyle(
fontSize: 18.0, fontWeight: FontWeight.w600),
),
],
),
),
DropdownMenuItem(
value: "2",
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Icon(MaterialCommunityIcons.solar_panel),
SizedBox(width: 10),
Text(
"Generation",
style: TextStyle(
fontSize: 18.0, fontWeight: FontWeight.w600),
),
],
),
),
],
),
if you want to see only an initial value you can use hint text named parameter of drop down button and set a text widget. i dont know whether it is a good practice or not.