Flutter DropDownButton value not changing after selecting a new value - flutter

I have been trying to make an external UI that a user can use to make certain changes to a database(dynamodb) in the cloud. When I select a new value, I want it to show the change that the user wants to make, without actually changing the database. The changes are saved only when I press a button on the appbar. Also when I use setState to rebuild the button, the value doesn't change on the cloud and it also changes the value for all of the buttons in the column(works fine without a setState). The code that I have provided changes the database when I press the save icon, but the drop-down button value stays the same unless I refresh the page. I apologize if I haven't explained my issue clearly enough, this is my first time posting on Stackoverflow, and I'm still learning about how to work with flutter and aws amplify.
body: InteractiveViewer(
constrained: false,
child: DataTable(
columns: [
DataColumn(label: Text('Apt #')),
DataColumn(label: Text('Type')),
DataColumn(label: Text('Availability')),
DataColumn(label: Text('Price')),
DataColumn(label: Text('Area'))
],
rows: aprts.map<DataRow>((element) { //aprts is a list that contains apartment objects.
return DataRow(cells: [
DataCell(Text(element.aptNum.toString())),
DataCell(Text(element.type)),
DataCell(DropdownButton<String>( /// this is the part im having problems wi
value: element.availabily, // gets the value for the availability attribute for the element and stores it into value.
onChanged: (String newValue) {
availValue = newValue; //stores the newValue in a global variable that is used in a function that is used toactually make changes to the database.
tempAvail = element;
},
items: <String>['AVAILABLE', 'SOLD', 'RESERVED']
.map((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
)), // end of problem.
DataCell(TextField(
controller: TextEditingController()
..text = element.price.toString(),
onChanged: (text) {
aptPrice = text;
tempPrice = element;
},
)),
DataCell(TextField(
controller: TextEditingController()..text = element.area,
onChanged: (text) {
aptArea = text;
tempArea = element;
},
)),
]);
}).toList()),
),
What the app looks like. After pressing the button

Use
onChanged: (String newValue) {
setState(() {
availValue = newValue;
tempAvail = element;
}
)
},
because for every change in the UI you must call setState((){})

Related

onChange does not get called for the PrefChoice in Flutter

I am using the flutter pref library to create a settings page. The PrefChoice is used to show a drop down for language selection. The drop down shows the values properly. Issue is when we select anything from the drop down, the onChange method does not get called for some reason. Due to this we are not able to take action on the change in choice. Is there anything I am missing here?
PrefChoice<String>(
title: Text(AppLocalization.of(context, 'settings.language')),
pref: 'language_key',
items: const [
DropdownMenuItem(
value: LocaleConstants.LC_ENGLISH,
child: Text(LocaleConstants.ENGLISH)),
DropdownMenuItem(
value: LocaleConstants.LC_GERMAN,
child: Text(LocaleConstants.GERMAN))
],
onChange: (value) {
// This never gets called
log.d('Locale changed to - $value');
},
),

Reload page after locale change

After changing locale in context.setLocale() language in inactive widgets change. But I cannot figure out, hoe to reload current widget in new locale. Any ideas how to get it working?
Body of widget:
Form(
child: CardSettings(
children: <CardSettingsSection>[
CardSettingsSection(
header: CardSettingsHeader(
label: 'settings.general'.tr(),
),
children: [
CardSettingsListPicker(
label: 'Language',
items: context.supportedLocales
.map((locale) =>
locale.toStringWithSeparator(separator: ' '))
.toList(),
initialItem:
context.locale.toStringWithSeparator(separator: ' '),
onChanged: (String newLocale) {
context.setLocale(newLocale.toLocale(separator: ' '));
_getOptions();
},
),
],
),
CardSettingsSection(
header: CardSettingsHeader(
label: 'Map',
),
children: [
CardSettingsListPicker(
label: 'default floor',
items: _floorList,
initialItem: _floor,
onChanged: (String value) {
var floor = tr('plan.floor.' + value);
_preferences.setString('mapDefaultFloor', floor);
},
),
],
),
],
),
);
And options are loaded via async function called in initState and later on in code...
void _getOptions() {
setState(() {
_floorList = Floor.values
.map((value) => tr('plan.floor.' + value.toString().split('.')[1]))
.toList();
_planTypeList = PlanType.values
.map((value) => tr('plan.type.' + value.toString().split('.')[1]))
.toList();
_floor = tr('plan.floor.' +
(_preferences.getString('mapDefaultFLoor') ?? 'ground'));
_planType = tr('plan.type.' +
(_preferences.getString('mapDefaultType') ?? 'newNumbers'));
});
}
stateful widgets automatically reload when you update their state. therefore, all you need to do is have your widget set as a StatefulWidget, and use the setState function to tell flutter that a change has been made to the state, and the widget needs to reload.
Taken from the flutter project template:
setState(() {
// This call to setState tells the Flutter framework that something has
// changed in this State, which causes it to rerun the build method below
// so that the display can reflect the updated values. If we changed
// _counter without calling setState(), then the build method would not be
// called again, and so nothing would appear to happen.
_counter++;
});
in the example showed above, the _counter is updated in the state, and in order for it to show the correct value on the app itself, the setState function is called.
Solution was to make _getOptions() async and add the locale change there with await keyword. This way it is ensured that locale is changed before loading new values...

Group radio button in listView

How to use group button in listView ? In each row, it has two radio button.
The problem now is if I select one of the radio button , the radio button not showing it is selected.
int value;
Map<int, bool> answers = {};
String _radioValue;
String choice;
int count = 0;
...item['questions']
.asMap()
.entries
.map((items) {
count++;
return TableRow(children: [
Padding(
padding: EdgeInsets.all(10),
child: Text(items.value['name'])),
Row(
children: [
Radio(
value: items.value['id'],
groupValue: count,
onChanged: (val) {
setSelectedRadioTile(val);
},
),
Text("Yes"),
Radio(
value: items.value['id'] + count,
groupValue: count,
onChanged: (val) {
setSelectedRadioTile(val);
},
),
Text("N/A")
],
)
]);
}).toList()
setSelectedRadioTile(int val) {
print(val);
setState(() {
count = val;
});
}
Okay well I have built you a working version based on what you provided here. Please keep in mind that it would probably be a good idea to look at the documentation more in-depth so you get a feeling of how some widgets behave and what specific properties (like groupValue) are for. Also keep in mind that the following code is not optimised or whatsoever, I just got it worked out for your case - thinking about how to structure your data overall is some fundamental thing you should take a look at. Maybe try some out some flutter courses which are available or look at some youtube content from known flutter coders. But now back to some code stuff.
I used those properties in my StatefulWidget to work with. Since you use some kind of question map and I don't know how it looks like, I just used something bare bones:
/// Map which has the question ID as its key and the answer from the user (currently true for yes and false for no (or n/a as in your case)
Map<int, bool> _answers = {};
/// Map which holds the information of your questions. Right now only an ID to be able to reference it and the actual question - again very bare bones
Map<String, dynamic> _item = {
'questions': [
{
'id': 0,
'question': 'Is this legit?',
},
{
'id': 1,
'question': 'Oh really?',
},
]
};
Then the method which will be called by the Radio widget once onChanged is triggered:
/// We need to know which question has been answered (therefore the ID) and which (bool) answer has been clicked by the user
_setSelectedRadioTile(int id, bool answer) {
setState(() {
_answers[id] = answer;
});
}
And now the widget part - since your code starts where you iterate over the questions, I also share this part specifically:
/// Since the map itself is typed as <String, dynamic>, accessing 'questions' will return dynamic. Only we, as we know the structure, know that this is indeed a list. Therefore we need to cast this as "List<dynamic>" so we can iterate over it and won't get exceptions
(_item['questions'] as List<dynamic>)
.map(
(question) => TableRow(children: [
Padding(
padding: EdgeInsets.all(10),
child: Text(question['question'])),
Row(
children: [
Radio(
/// The [value] property of Radio tells us, which property is used in [onChanged] - therefore now once this Radio is clicked, true is provided in the [onChanged] callback
value: true,
/// [groupValue] is the value which this Radio is bound to. As you probably know, only one Radio button should be active for a group. So if you have a question which has several possible answers as radio buttons, we only want one of them to be active at a time. Thats what the [groupValue] is for. Since we iterate over all questions and every entity of a question (currently) has two possible answers (Yes and N/A), both those answers are for a specific question - the question with the current ID
groupValue: _answers[question['id']],
onChanged: (answer) {
_setSelectedRadioTile(question['id'], answer);
},
),
Text("Yes"),
Radio(
value: false,
groupValue: _answers[question['id']],
onChanged: (answer) {
_setSelectedRadioTile(question['id'], answer);
},
),
Text("N/A")
],
)
]),
)
.toList(),
This should work on your side once you updated this example to fit with your data model. Again: I advise you to think about how you structure your data generally.

Dropdown box not displaying selected value

When I select a value from my dropdown the hint text does not change:
String fontSizeValue;
new DropdownButton<String>(
items: new List<double>.generate(72, (i) => i + 2.0).map((double value) {
return new DropdownMenuItem<String>(
value: value.toString(),
child: new Text(value.toString()),
);
}).toList(),
onChanged: (String _) {
setState(() {
fontSize = double.parse(_);
fontSizeValue = _;
print(fontSizeValue);
});
},
value: fontSizeValue,
hint: Text('Select'),
)),
],
),
),
);
Any idea how I can get the selected value to show instead of "select"? Thanks
You did not post enough code, but I'll take a wild guess anyway, because there are a lot of questions with this problem:
Your variable String fontSizeValue; is defined locally, probably in the build function.
You have to define it in a wider scope, so it will retain it's value after another call to build that will happen when you call setState. Probably as a class member of your State class.

Flutter drop down works but doesn't display updated value

My dropdown menu works properly after selecting a new option, but the new selection doesn't update the currently displayed option after its changed.
Widget buildCarDropdown() {
return
Center(
child: DropdownButton(
hint: Text('Please choose a car make'),
value: currentLease.carMake,
onChanged: (newValue) {
setState(() {
currentLease.carMake = newValue;
});
},
items: carMakes.map((String make) {
return DropdownMenuItem(
child: new Text(make),
value: make,
);
}).toList(),
),
);
}
carMakes is just an array of strings
currentLease contains a string for the selection of make. The value is set correctly after changing it in currentLease, and displays correctly if the widget is reloaded.
Everything seems proper here to me, not sure why it doesn't display updates properly.
Edit: What I mean by not updating it, that the drop down opens displaying all the options. Say it started at "Honda", you can then select "Acura" and though the currentLease.carMake gets updated properly, the drop down stays displaying "Honda" until it is reloaded.