Error while displaying value in drop down menu - flutter

I have implemented a dropdownmenu in which we have select university. Based on the university you get the option,for eg: if University of Mumbai is being selected only Computer Engineering is shown for selecting the department,while for University of Pune all the departments are shown.
Dropdownmenu works properly but the value selected in the menu is not displayed.
When i implement the parameter value i get the below 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
'package:flutter/src/material/dropdown.dart':
Failed assertion: line 827 pos 15: 'items == null || items.isEmpty || value == null ||
items.where((DropdownMenuItem<T> item) {
return item.value == value;
}).length == 1'
This is the code i implemented:
var _universities = ["Savitribai Phule Pune University" , "University of Mumbai" , "other"];
List<DropdownMenuItem<String>> menuitems = List();
final sppu = {
"1" : "Computer Engineering",
"2" : "Electronics & Telecommunications",
"3" : "Information Technology",
"4" : "Mechanical Engineering"
};
final uom = {
"1" : "Computer Engineering",
};
final other = {
"1" : "Inactive",
};
void populatesppu(){
for(String key in sppu.keys){
menuitems.add(DropdownMenuItem<String>(
value: sppu[key],
child: Center(
child: Text(
sppu[key],
),
),
));
}
}
void populateuom(){
for(String key in uom.keys){
menuitems.add(DropdownMenuItem<String>(
value: uom[key],
child: Center(
child: Text(
uom[key],
),
),
));
}
}
void populateother(){
for(String key in other.keys){
menuitems.add(DropdownMenuItem<String>(
value: other[key],
child: Center(
child: Text(
other[key],
),
),
));
}
}
void valuechanged(_value){
if(_value == "Savitribai Phule Pune University"){
menuitems = [];
populatesppu();
}else if(_value == "University Of Mumbai"){
menuitems = [];
populateuom();
}else if(_value == "Other"){
menuitems = [];
populateother();
}
setState(() {
value = _value;
_currentval = _value;
disabledropdown = false;
});
}
void secondvaluechanged(_value){
setState(() {
value = _value;
_currentval2 =_value;
});
}
Column(
children: <Widget>[
Container(
decoration: BoxDecoration(
color: bgColor,
),
padding: EdgeInsets.only(left: 20,top: 20,right: 20),
child: Form(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text("University Details",
style: TextStyle(color: Colors.white,fontSize: 22,fontWeight: FontWeight.bold),),
SizedBox(height: 10,),
Padding(
padding: EdgeInsets.all(5.0),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
padding: EdgeInsets.only(left: 12.0,right: 12.0),
decoration: BoxDecoration(
border: Border.all(color: Colors.white,width: 2.0),
borderRadius: BorderRadius.circular(12.0),
),
child: DropdownButton<String>(
items:[
DropdownMenuItem<String>(
value: "Savitribai Phule Pune University",
child: Center(
child: Text("Savitribai Phule Pune University"),
),
),
DropdownMenuItem<String>(
value: "University Of Mumbai",
child: Center(
child: Text("University Of Mumbai"),
),
),
DropdownMenuItem<String>(
value: "Other",
child: Center(
child: Text("Other"),
),
)
],
onChanged: (_value) => valuechanged(_value),
hint:Text("SELECT UNIVERSITY",
style: TextStyle(color: Colors.white),),
elevation: 5,
icon: Icon(Icons.arrow_drop_down,color: Colors.black,),
iconSize: 36,
isExpanded: true,
style: TextStyle(color: Colors.black,fontSize: 20),
//value: _currentval,
//value: value,
),
),
),
),
Padding(
padding: EdgeInsets.all(5.0),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
padding: EdgeInsets.only(left: 12.0,right: 12.0),
decoration: BoxDecoration(
border: Border.all(color: Colors.white,width: 2.0),
borderRadius: BorderRadius.circular(12.0),
),
child: DropdownButton<String>(
items:
menuitems,
onChanged: disabledropdown ? null : (_value) => secondvaluechanged(_value),
hint: Text(
"SELECT DEPARTMENT",
style: TextStyle(color: Colors.white)),
disabledHint: Text(
"First Select Any University",
style: TextStyle(color: Colors.white),
),
elevation: 5,
icon: Icon(Icons.arrow_drop_down,color: Colors.black,),
iconSize: 36,
isExpanded: true,
style: TextStyle(color: Colors.black,fontSize: 18),
//value: _currentval2,
//value: value,
),
),
),
),
SizedBox(height: 4,),
Padding(
padding: const EdgeInsets.all(5.0),
child: Container(
padding: EdgeInsets.only(left: 12.0,right: 12.0),
child: TextFormField(
decoration: InputDecoration(
labelText: "College/Organization(in short)",
labelStyle: TextStyle(color: Colors.white,fontSize: 19),
),
style: TextStyle(color: Colors.white,fontSize: 23),
onChanged: (val) {
setState(() {
name=val;
});
},
),
),
),
SizedBox(height: 10,),
RaisedButton(
textColor: Colors.deepPurple,
onPressed: ()async {},
color: Colors.white,
child: Text("ADD",
textAlign: TextAlign.center,
style: TextStyle(fontSize: 17,
fontWeight: FontWeight.bold),
),
),
//Text("$value",),
],
),
)
),
SizedBox(height: 20,),
]
,),

I hope this will help, when _changeDept() is called, don't forget to update department to default value Select or something. In your case, you should change in valuechanged(). In case you don't want to use Select as default value, _selectedDeptVal = _getDeptItem(_selectedUniVal).first
class _MyHomePageState extends State<MyHomePage> {
final _universities = const [
"Savitribai Phule Pune University",
"University of Mumbai",
"other",
];
final sppu = const {
"1": "Computer Engineering",
"2": "Electronics & Telecommunications",
"3": "Information Technology",
"4": "Mechanical Engineering"
};
final uom = const {
"1": "Computer Engineering",
};
final other = const {
"1": "Inactive",
};
var _selectedUniVal;
var _selectedDeptVal = 'Select';
List<String> _deptItem = ['Select'];
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Container(
padding: const EdgeInsets.all(20),
child: Column(
children: <Widget>[
DropdownButton(
value: _selectedUniVal,
onChanged: (val) => _changeDept(currentUni: val),
items: _universities.map(
(item) {
return DropdownMenuItem(
child: Text('$item'),
value: item,
);
},
).toList(),
),
DropdownButton(
value: _selectedDeptVal,
onChanged: (val) => setState(() => _selectedDeptVal = val),
items: _deptItem.map(
(item) {
return DropdownMenuItem(
child: Text('$item'),
value: item,
);
},
).toList(),
),
],
),
),
),
);
}
void _changeDept({String currentUni}) {
setState(
() {
// update current university
_selectedUniVal = currentUni;
// reset dept val
_selectedDeptVal = 'Select';
// update corresponding department
// clear list
_deptItem = ['Select'];
_deptItem.addAll(_getDeptItem(_selectedUniVal));
},
);
}
List<String> _getDeptItem(String currentUni) {
switch (currentUni) {
case 'Savitribai Phule Pune University':
return sppu.values.toList();
break;
case 'University of Mumbai':
return uom.values.toList();
break;
case 'other':
default:
return other.values.toList();
}
}
}
[Edited]
When [Pune and Mechanical Engineering] is selected state, even you change to [Mumbai], department value is still holding [Mechanical Engineering]. Actually, [Mechanical Engineering] isn't in the uom. That's the problem. So, you have to update _selectedDeptVal.

Related

Why is my flutter widgets not working when in a different state management

I bought an online template app and i am trying to hardcode my email and password credentials in my flutter frontend because i don't have access to the backend api yet to change from email/password auth to phone auth, so i want to force code the logic into my flutter widget.
This means i am trying to implement the onPressed: () { controller.login(); }, function on a login button to get me to the home screen with my customized widget.
The original code given to me works fine when i hardcode the credentials in the text form field but when i hardcode the text form field in my customized widget and use same onPressed: () { controller.login(); }, function it don't work.
I want to know if it's because of i'm in a different state management or there's something i'm failing to do.
I will give the original code and my customized UI code in the snippets for comparison.
PS: i even tried to use same text form field in my widget but hide it with Visibility() in flutter. When i use Visibility() in the original code, onPressed: () { controller.login(); }, works but when i use it in my customized widget, it doest.
How do work around this? If you need more clarification, i am willing to offer. Thanks.
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../../../../../common/helper.dart';
import '../../../../../common/ui.dart';
import '../../../../models/setting_model.dart';
import '../../../../routes/app_routes.dart';
import '../../../../services/settings_service.dart';
import '../../../global_widgets/block_button_widget.dart';
import '../../../global_widgets/circular_loading_widget.dart';
import '../../../global_widgets/text_field_widget.dart';
import '../../controllers/auth_controller.dart';
class LoginView extends GetView<AuthController> {
final Setting _settings = Get.find<SettingsService>().setting.value;
#override
Widget build(BuildContext context) {
controller.loginFormKey = new GlobalKey<FormState>();
return Visibility(
visible: false,
child: WillPopScope(
onWillPop: Helper().onWillPop,
child: Scaffold(
appBar: AppBar(
title: Text(
"Login".tr,
style: Get.textTheme.headline6
.merge(TextStyle(color: context.theme.primaryColor)),
),
centerTitle: true,
backgroundColor: Get.theme.colorScheme.secondary,
automaticallyImplyLeading: false,
elevation: 0,
),
body: Form(
key: controller.loginFormKey,
child: ListView(
primary: true,
children: [
Stack(
alignment: AlignmentDirectional.bottomCenter,
children: [
Container(
height: 180,
width: Get.width,
decoration: BoxDecoration(
color: Get.theme.colorScheme.secondary,
borderRadius:
BorderRadius.vertical(bottom: Radius.circular(10)),
boxShadow: [
BoxShadow(
color: Get.theme.focusColor.withOpacity(0.2),
blurRadius: 10,
offset: Offset(0, 5)),
],
),
margin: EdgeInsets.only(bottom: 50),
child: Padding(
padding: const EdgeInsets.all(20),
child: Column(
children: [
Text(
_settings.salonAppName,
style: Get.textTheme.headline6.merge(TextStyle(
color: Get.theme.primaryColor, fontSize: 24)),
),
SizedBox(height: 5),
Text(
"Welcome to the best salon service system!".tr,
style: Get.textTheme.caption.merge(
TextStyle(color: Get.theme.primaryColor)),
textAlign: TextAlign.center,
),
// Text("Fill the following credentials to login your account", style: Get.textTheme.caption.merge(TextStyle(color: Get.theme.primaryColor))),
],
),
),
),
Container(
decoration: Ui.getBoxDecoration(
radius: 14,
border:
Border.all(width: 5, color: Get.theme.primaryColor),
),
child: ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(10)),
child: Image.asset(
'assets/icon/icon.png',
fit: BoxFit.cover,
width: 100,
height: 100,
),
),
),
],
),
Obx(() {
if (controller.loading.isTrue)
return CircularLoadingWidget(height: 300);
else {
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Visibility(
visible: false,
maintainState: true,
child: TextFieldWidget(
labelText: "Email Address".tr,
hintText: "johndoe#gmail.com".tr,
initialValue: 'salon#demo.com',
onSaved: (input) =>
controller.currentUser.value.email = input,
validator: (input) => !input.contains('#')
? "Should be a valid email".tr
: null,
iconData: Icons.alternate_email,
),
),
Obx(() {
return Visibility(
visible: false,
maintainState: true,
child: TextFieldWidget(
labelText: "Password".tr,
hintText: "••••••••••••".tr,
initialValue: '123456',
onSaved: (input) =>
controller.currentUser.value.password = input,
validator: (input) => input.length < 3
? "Should be more than 3 characters".tr
: null,
),
);
}),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
TextButton(
onPressed: () {
Get.toNamed(Routes.FORGOT_PASSWORD);
},
child: Text("Forgot Password?".tr),
),
],
).paddingSymmetric(horizontal: 20),
BlockButtonWidget(
onPressed: () {
controller.login();
},
color: Get.theme.colorScheme.secondary,
text: Text(
"Login".tr,
style: Get.textTheme.headline6.merge(
TextStyle(color: Get.theme.primaryColor)),
),
).paddingSymmetric(vertical: 10, horizontal: 20),
TextButton(
onPressed: () {
//Get.toNamed(Routes.REGISTER);
},
child: Text("You don't have an account?".tr),
).paddingOnly(top: 20),
GestureDetector(
onTap: () {
Get.toNamed(Routes.SETTINGS_LANGUAGE);
},
child: Text(
Get.locale.toString().tr,
textAlign: TextAlign.center,
),
),
],
);
}
}),
],
),
),
),
),
);
}
}
THIS IS THE ORIGINAL WIDGET CODE
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../../../../routes/app_routes.dart';
import '../../../global_widgets/circular_loading_widget.dart';
import '../../../global_widgets/text_field_widget.dart';
import '../../controllers/auth_controller.dart';
import 'login_view.dart';
import 'pin_number.dart';
import 'keyboard_number.dart';
class PinScreen extends StatefulWidget {
const PinScreen({Key key}) : super(key: key);
#override
State<PinScreen> createState() => _PinScreenState();
}
class _PinScreenState extends State<PinScreen> {
List<String> currentPin = ["", "", "", ""];
TextEditingController pinOneController = TextEditingController();
TextEditingController pinTwoController = TextEditingController();
TextEditingController pinThreeController = TextEditingController();
TextEditingController pinFourController = TextEditingController();
var outlineInputBorder = OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: BorderSide(color: Colors.transparent),
);
int pinIndex = 0;
#override
Widget build(BuildContext context) {
final controller = Get.find<AuthController>();
controller.loginFormKey = new GlobalKey<FormState>();
return Form(
key: controller.loginFormKey,
child: SafeArea(
child: Column(
children: [
buildExitButton(),
Obx(() {
if (controller.loading.isTrue)
return CircularLoadingWidget(height: 300);
else {
return Expanded(
child: Container(
alignment: Alignment(0, 0.5),
padding: EdgeInsets.symmetric(horizontal: 16.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
buildSecurityText(),
SizedBox(height: 20.0),
buildPinRow(),
SizedBox(height: 10.0),
buildNumberPad(),
SizedBox(height: 20.0),
Visibility(
visible: false,
maintainState: true,
child: TextFieldWidget(
labelText: "Email Address".tr,
hintText: "johndoe#gmail.com".tr,
initialValue: 'salon#demo.com',
validator: (input) => !input.contains('#')
? "Should be a valid email".tr
: null,
iconData: Icons.alternate_email,
),
),
Obx(() {
return Visibility(
visible: false,
maintainState: true,
child: TextFieldWidget(
labelText: "Password".tr,
hintText: "••••••••••••".tr,
initialValue: '123456',
validator: (input) => input.length < 3
? "Should be more than 3 characters".tr
: null,
iconData: Icons.lock_outline,
keyboardType: TextInputType.visiblePassword,
suffixIcon: IconButton(
onPressed: () {
controller.hidePassword.value =
!controller.hidePassword.value;
},
color: Theme.of(context).focusColor,
icon: Icon(controller.hidePassword.value
? Icons.visibility_outlined
: Icons.visibility_off_outlined),
),
),
);
}),
Container(
child: new RichText(
text: new TextSpan(
children: [
new TextSpan(
recognizer: TapGestureRecognizer()
..onTap = () {
// Get.toNamed(Routes.REGISTER);
},
text: 'Forgot Pin ?',
style: new TextStyle(
color: Color(0xff3498DB),
fontSize: 14,
fontWeight: FontWeight.w500),
),
],
),
),
),
SizedBox(height: 20.0),
MaterialButton(
onPressed: () {
controller.login();
},
color: Color(0xff34495E),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20.18),
),
padding: EdgeInsets.symmetric(
horizontal: 30, vertical: 10),
minWidth: double.infinity,
child: Text(
'Next',
style: TextStyle(
color: Colors.white,
fontSize: 16,
fontWeight: FontWeight.w600),
),
),
SizedBox(height: 32.0),
],
),
),
);
}
})
],
),
),
);
}
buildNumberPad() {
return Expanded(
child: Container(
alignment: Alignment.bottomCenter,
child: Padding(
padding: const EdgeInsets.only(bottom: 12),
child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
KeyboardNumber(
n: 1,
onPressed: () {
pinIndexSetup("1");
},
),
KeyboardNumber(
n: 2,
onPressed: () {
pinIndexSetup("2");
},
),
KeyboardNumber(
n: 3,
onPressed: () {
pinIndexSetup("3");
},
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
KeyboardNumber(
n: 4,
onPressed: () {
pinIndexSetup("4");
},
),
KeyboardNumber(
n: 5,
onPressed: () {
pinIndexSetup("5");
},
),
KeyboardNumber(
n: 6,
onPressed: () {
pinIndexSetup("6");
},
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
KeyboardNumber(
n: 7,
onPressed: () {
pinIndexSetup("7");
},
),
KeyboardNumber(
n: 8,
onPressed: () {
pinIndexSetup("8");
},
),
KeyboardNumber(
n: 9,
onPressed: () {
pinIndexSetup("9");
},
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Container(
width: 60.0,
child: MaterialButton(
onPressed: null,
child: SizedBox(),
),
),
KeyboardNumber(
n: 0,
onPressed: () {
pinIndexSetup("0");
},
),
Container(
width: 60.0,
child: MaterialButton(
onPressed: () {
clearPin();
},
height: 60.0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(60.0),
),
child: Image.asset(
'assets/icon/clear-symbol.png',
),
),
)
],
),
],
),
),
),
);
}
clearPin() {
if (pinIndex == 0)
pinIndex = 0;
else if (pinIndex == 4) {
setPin(pinIndex, "");
currentPin[pinIndex - 1] = "";
pinIndex--;
} else {
setPin(pinIndex, "");
currentPin[pinIndex - 1] = "";
pinIndex--;
}
}
pinIndexSetup(String text) {
if (pinIndex == 0)
pinIndex = 1;
else if (pinIndex < 4) pinIndex++;
setPin(pinIndex, text);
currentPin[pinIndex - 1] = text;
String strPin = "";
currentPin.forEach((e) {
strPin += e;
});
if (pinIndex == 4) print(strPin);
}
setPin(int n, String text) {
switch (n) {
case 1:
pinOneController.text = text;
break;
case 2:
pinTwoController.text = text;
break;
case 3:
pinThreeController.text = text;
break;
case 4:
pinFourController.text = text;
break;
}
}
buildExitButton() {
return Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: MaterialButton(
onPressed: () {
Navigator.pop(context);
},
height: 50.0,
minWidth: 50.0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(50.0),
),
child: Icon(
Icons.clear,
color: Colors.black54,
),
),
),
],
);
}
buildSecurityText() {
return Column(
children: [
Align(
alignment: Alignment.topLeft,
child: Text(
'Enter PIN',
style: TextStyle(
color: Color(0xff151515),
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
),
SizedBox(
height: 12,
),
Align(
alignment: Alignment.topLeft,
child: Padding(
padding: const EdgeInsets.only(right: 80),
child: Text(
'Enter 4 digit PIN to access your account ',
style: TextStyle(
color: Color(0xff151515),
fontSize: 14,
fontWeight: FontWeight.w500,
fontStyle: FontStyle.normal,
),
),
),
),
],
);
}
buildPinRow() {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
PINNumber(
outlineInputBorder: outlineInputBorder,
textEditingController: pinOneController,
),
PINNumber(
outlineInputBorder: outlineInputBorder,
textEditingController: pinTwoController,
),
PINNumber(
outlineInputBorder: outlineInputBorder,
textEditingController: pinThreeController,
),
PINNumber(
outlineInputBorder: outlineInputBorder,
textEditingController: pinFourController,
),
],
);
}
}
THIS IS MY CUSTOMIZED WIDGET TREE/CODE

The state of my checkboxes keep returning to their original value in flutter

I have a profile page with some widgets which after saving and redrawing, they keep their new states, but my checkboxes do not, and I have not modified them at all. The new value is being saved on the database, but on the UI it's not preserved. If I turn the email checkbox to true, the 'true' boolean is saved, but it's not displayed on the frontend after pressing the submit button.
class _ProfilePageState extends State<ProfilePage> {
final _formKey = GlobalKey<FormState>();
bool? emailIsChecked = false;
bool? smsisChecked = false;
bool isTextFieldEnabled = false;
bool isIgnored = true;
bool isVisible = false;
bool editIsVisible = true;
bool emailIsEnabled = false;
bool smsIsEnabled = false;
bool nameEdit = false;
late TextEditingController countryController;
late TextEditingController languageController;
#override
void initState() {
super.initState();
countryController = TextEditingController(text: globals.signedInUser!.country);
languageController = TextEditingController(text: globals.signedInUser!.language);
selectedCountry = globals.signedInUser!.country;
selectedLanguage = globals.signedInUser!.language;
globals.signedInUser!.notifications.forEach(
(element) {
if ((element['type']) == 'Email') {
emailIsChecked = element['status'];
}
if ((element['type']) == 'SMS') {
smsisChecked = element['status'];
}
},
);
cleanInputStates();
}
#override
void dispose() {
countryController.dispose();
languageController.dispose();
super.dispose();
}
checkEditVisibility() {
if (editIsVisible == true) {
return true;
}
if (editIsVisible == false) {
return false;
}
}
checkEditAvailability() {
if (editIsVisible == false) {
return true;
}
if (editIsVisible == true) {
return false;
}
}
cleanInputStates() {
isTextFieldEnabled = false;
isIgnored = true;
editIsVisible = true;
isVisible = false;
smsIsEnabled = false;
emailIsEnabled = false;
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Form(
key: _formKey,
child: Row(
children: [
Flexible(
flex: 5,
child: Padding(
padding: const EdgeInsets.only(top: 20),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
height: 30,
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Visibility(
visible: editIsVisible,
maintainSize: true,
maintainAnimation: true,
maintainState: true,
child: ElevatedButton.icon(
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(Colors.green)),
icon: const Icon(Icons.edit),
label: Text('Edit'),
onPressed: () {
setState(() {
isTextFieldEnabled = true;
isIgnored = false;
isVisible = true;
editIsVisible = false;
smsIsEnabled = true;
emailIsEnabled = true;
});
}),
),
SizedBox(
width: 250,
)
],
),
SizedBox(
height: 30,
),
Flexible(
flex: 1,
child: Padding(
padding: const EdgeInsets.only(top: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
height: 20,
),
... // TextFieldInputs
Row(
children: [
Container(
child: Text(
"Country: ",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 22,
color: Colors.black.withOpacity(0.3),
),
),
),
SizedBox(
width: 100,
),
Container(
width: 300,
child: IgnorePointer(
ignoring: isIgnored,
child: DropdownButtonFormField2(
decoration: InputDecoration(
isDense: true,
contentPadding: EdgeInsets.zero,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(15),
),
),
isExpanded: true,
hint: const Text(
'Select Your Country',
style: TextStyle(fontSize: 14),
),
icon: const Icon(
Icons.arrow_drop_down,
color: Colors.black45,
),
iconSize: 30,
buttonHeight: 60,
buttonPadding: const EdgeInsets.only(left: 20, right: 10),
dropdownDecoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
),
items: countryItems
.map((item) => DropdownMenuItem<String>(
value: item,
child: Text(
item,
style: const TextStyle(
fontSize: 14,
),
),
))
.toList(),
validator: (valueCountry) {
if (valueCountry == null) {
return 'Please select country.';
}
return null;
},
value: selectedCountry,
onChanged: (String? valueCountry) {
selectedCountry = valueCountry;
setState(() {
valueCountry;
});
},
),
),
),
// ),
],
),
SizedBox(
height: 20,
),
Row(
children: [
Container(
child: Text(
"Language: ",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 22,
color: Colors.black.withOpacity(0.3),
),
),
),
SizedBox(
width: 80,
),
Container(
width: 300,
child: IgnorePointer(
ignoring: isIgnored,
child: DropdownButtonFormField2(
decoration: InputDecoration(
isDense: true,
contentPadding: EdgeInsets.zero,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(15),
),
),
isExpanded: true,
hint: const Text(
'Select Your Language',
style: TextStyle(fontSize: 14),
),
icon: const Icon(
Icons.arrow_drop_down,
color: Colors.black45,
),
iconSize: 30,
buttonHeight: 60,
buttonPadding: const EdgeInsets.only(left: 20, right: 10),
dropdownDecoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
),
items: languageItems
.map((item) => DropdownMenuItem<String>(
value: item,
child: Text(
item,
style: const TextStyle(
fontSize: 14,
),
),
))
.toList(),
value: selectedLanguage,
validator: (valueLanguage) {
if (valueLanguage == null) {
return 'Please select language.';
}
return null;
},
onChanged: (String? valueLanguage) {
selectedLanguage = valueLanguage;
setState(() {
valueLanguage;
});
},
),
),
),
// ),
],
),
Row()
],
),
SizedBox(
width: 120,
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Container(
child: Row(
children: [
Text(
"Receive notifications by: ",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 22,
color: Colors.black.withOpacity(0.3),
),
),
],
),
),
],
),
SizedBox(
height: 10,
),
Row(
children: [
Container(
width: 300,
child: CheckboxListTile(
enabled: emailIsEnabled,
title: Text("E-mail"),
value: emailIsChecked,
onChanged: (bool? newEmailValue) {
setState(() {
emailIsChecked = newEmailValue;
});
},
activeColor: Colors.green,
),
),
],
),
Row(
children: [
Container(
width: 300,
child: CheckboxListTile(
enabled: smsIsEnabled,
title: Text("SMS"),
value: smsisChecked,
onChanged: (bool? newSmsValue) {
setState(() {
smsisChecked = newSmsValue;
});
},
activeColor: Colors.green,
),
),
],
),
SizedBox(
height: 100,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Visibility(
visible: isVisible,
child: Row(
children: <Widget>[
ElevatedButton(
style: ButtonStyle(
backgroundColor:
MaterialStateProperty.all(Colors.red)),
onPressed: () {
setState(() {
cleanInputStates();
_formKey.currentState!.reset();
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ProfilePage()));
});
print("Cleaning states");
},
child: Text("Dismiss"),
),
SizedBox(
width: 100,
),
ElevatedButton(
style: ButtonStyle(
backgroundColor:
MaterialStateProperty.all(Colors.green)),
onPressed: () {
if (_formKey.currentState!.validate()) {
final userInfo = {
"_id": globals.signedInUser!.userId,
"firstName": firstnameTextController.text,
"lastName": lastnameTextController.text,
"email": emailTextController.text,
"phoneNumber": phoneNumberTextController.text,
"country": selectedCountry.toString(),
"language": selectedLanguage.toString(),
"notifications": [
{"type": "Email", "status": emailIsChecked},
{"type": "SMS", "status": smsisChecked}
]
};
globals.socketController.updateUser(userInfo);
Fluttertoast.showToast(
msg: "Applying changes.", // message
toastLength: Toast.LENGTH_LONG, // length
gravity: ToastGravity.BOTTOM_RIGHT, // location
timeInSecForIosWeb: 2,
webBgColor: "#4caf50",
);
}
print("DATA IS BEING SAVED");
setState(() {
if (_formKey.currentState!.validate()) {
globals.signedInUser!.email =
emailTextController.text;
globals.signedInUser!.phoneNumber =
phoneNumberTextController.text;
globals.signedInUser!.firstName =
firstnameTextController.text;
globals.signedInUser!.lastName =
lastnameTextController.text;
globals.signedInUser!.country =
selectedCountry as String;
globals.signedInUser!.language =
selectedLanguage as String;
cleanInputStates();
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ProfilePage()));
} else {
print("ingresando else");
}
});
},
child: Text("Save"),
),
],
),
)
],
)
],
),
],
),
),
),
],
), //Column ends here
),
),
],
),
),
);
}
}
Update: After some testings and workarounds, I found that the second issue was due to not assigning a new value prior to returning to the initState. To do that, I added the following code segment into the setState() of the submit button, which is the fetch of the notification parameters within the initState() but assigning the new checkbox values into the array. Additionally, I removed the cleanInputStates(); on the initState as #Paulo mentioned and everything else kept the same.
globals.signedInUser!.notifications.forEach(
(element) {
if ((element['type']) == 'Email') {
element['status'] = emailIsChecked;
}
if ((element['type']) == 'SMS') {
element['status'] = smsisChecked;
}
},
);

flutter bloc doesn't update the ui?

when i navigate from NewSales screen to CreateItem screen and add item and press the add button
the item is added to sqflite database then it navigates back to new sales but the state is not updated , it's updated only if i restarted the app
the NewSales screen
class _NewSalesState extends State<NewSales> {
final controller = TextEditingController();
showAlertDialog(BuildContext context,String name) {
// Create button
// Create AlertDialog
AlertDialog alert = AlertDialog(
title: const Text("Alert"),
content: const Text("you want to delete this item?"),
actions: [
TextButton(
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(Colors.green)),
child: const Text("CANCEL", style: TextStyle(color: Colors.white)),
onPressed: () {
Navigator.of(context).pop();
},
),
BlocBuilder<SalesCubit, SalesState>(
builder: (context, state) {
final bloc=BlocProvider.of<SalesCubit>(context);
return TextButton(
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(Colors.red)),
child: const Text(
"DELETE",
style: TextStyle(color: Colors.white),
),
onPressed: () {
Navigator.of(context).pop();
bloc.deleteItem(name).then((value) {
bloc.getAllItems();
});
},
);
},
)
],
);
// show the dialog
showDialog(
context: context,
builder: (BuildContext context) {
return alert;
},
);
}
// #override
#override
Widget build(BuildContext context) {
final deviceSize = MediaQuery
.of(context)
.size;
return BlocConsumer<SalesCubit, SalesState>(
listener: (context, state) {},
builder: (context, state) {
final bloc = BlocProvider.of<SalesCubit>(context);
if (state is SalesInitial) {
bloc.getAllItems();
}
return Scaffold(
drawer: const navDrawer(),
appBar: AppBar(
title: const Text("Ticket"),
actions: [
IconButton(
onPressed: () async {
String barcodeScanRes;
// Platform messages may fail, so we use a try/catch PlatformException.
try {
barcodeScanRes = await FlutterBarcodeScanner.scanBarcode(
'#ff6666', 'Cancel', true, ScanMode.BARCODE);
print('barcodeScanRes $barcodeScanRes');
print(bloc.bsResult);
} on PlatformException {
barcodeScanRes = 'Failed to get platform version.';
}
// If the widget was removed from the tree while the asynchronous platform
// message was in flight, we want to discard the reply rather than calling
// setState to update our non-existent appearance.
if (!mounted) return;
bloc.toggleSearch();
controller.text = barcodeScanRes;
bloc.filterItems(barcodeScanRes);
},
icon: const Icon(Icons.scanner),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: IconButton(
onPressed: () {
Navigator.of(context).pushNamed(Routes.addCustomerRoute);
},
icon: Icon(Icons.person_add)),
),
],
),
body: Column(
children: [
// the first button
Container(
width: double.infinity,
height: deviceSize.height * .1,
color: Colors.grey,
child: GestureDetector(
onTap: ()=>displayMessage("an item was charged successfully", context),
child: Padding(
padding: const EdgeInsets.all(10),
child: Container(
color: Colors.green,
child: const Center(
child: Text("charge",style: TextStyle(color: Colors.white),),
),
),
),
),
),
// the second container
SizedBox(
width: deviceSize.width,
height: deviceSize.height * .1,
child: Row(
children: [
DecoratedBox(
decoration:
BoxDecoration(border: Border.all(color: Colors.grey)),
child: SizedBox(
width: deviceSize.width * .8,
child: bloc.isSearch
? TextFormField(
autofocus: true,
controller: controller,
decoration:
const InputDecoration(hintText: "Search"),
onChanged: (value) {
bloc.filterItems(controller.text);
},
)
: DropdownButtonFormField<String>(
// underline: Container(),
// value: "Discounts",
hint: const Padding(
padding: EdgeInsets.only(left: 10),
child: Text('Please choose type'),
),
items: <String>['Discounts', 'All Items']
.map((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
onChanged: (_) {},
),
),
),
DecoratedBox(
decoration:
BoxDecoration(border: Border.all(color: Colors.grey)),
child: SizedBox(
width: deviceSize.width * .2,
child: IconButton(
onPressed: () {
bloc.toggleSearch();
if (!bloc.isSearch) {
bloc.filterItems('');
}
},
icon: Icon(
!bloc.isSearch ? Icons.search : Icons.close)),
),
)
],
),
),
// the third container
if (state is IsLoading || state is SalesInitial)
const Center(
child: CircularProgressIndicator(
color: Colors.green,
backgroundColor: Colors.green,
),
),
if (state is Loaded || state is IsSearch || state is SearchDone)
bloc.items.isEmpty
? const Center(
child: Text("no items added yet"),
)
: Expanded(
child: bloc.filteredItems.isEmpty
? const Center(
child: Text(
"no items found with this name",
style: TextStyle(color: Colors.green),
),
)
: ListView.builder(
itemCount: bloc.filteredItems.length,
itemBuilder: (context, i) {
final item = bloc.filteredItems[i];
return Card(
child: ListTile(
leading: CircleAvatar(
backgroundColor: Colors.green,
radius: 20,
child: Text(item.price),
),
title: Text(item.name),
subtitle: Text(item.barcode),
trailing: Column(
children: [
IconButton(
onPressed: () {
showAlertDialog(context,item.name);
// bloc.deleteItem(item.name).then((value) {
// bloc.getAllItems();
// });
},
icon: const Icon(
Icons.delete,
color: Colors.red,
))
],
)),
);
}))
],
),
floatingActionButton: FloatingActionButton(
child: const Icon(Icons.add),
onPressed: ()async {
Navigator.of(context).pushNamed(Routes.createItemRoute);
},
),
);
},
);
}
}
the CreateItem screen
class _CreateItemState extends State<CreateItem> {
final nameController = TextEditingController();
final priceController = TextEditingController();
final costController = TextEditingController();
final skuController = TextEditingController();
final barcodeController = TextEditingController();
final inStockController = TextEditingController();
bool each = true; // bool variable for check box
bool isColor = true;
bool switchValue = false;
File? file;
String base64File = "";
String path = "";
final _formKey = GlobalKey<FormState>();
#override
void dispose() {
nameController.dispose();
priceController.dispose();
costController.dispose();
skuController.dispose();
barcodeController.dispose();
inStockController.dispose();
super.dispose();
}
Future pickImage(ImageSource source) async {
File? image1;
XFile imageFile;
final imagePicker = ImagePicker();
final image = await imagePicker.pickImage(source: source);
imageFile = image!;
image1 = File(imageFile.path);
List<int> fileUnit8 = image1.readAsBytesSync();
setState(() {
base64File = base64.encode(fileUnit8);
});
}
#override
Widget build(BuildContext context) {
final deviceSize = MediaQuery.of(context).size;
return BlocProvider(
create: (BuildContext context) => CreateItemCubit(),
child: Builder(builder: (context){
final bloc=BlocProvider.of<CreateItemCubit>(context);
return Scaffold(
appBar: AppBar(
leading: IconButton(
onPressed: () => Navigator.of(context).pushNamedAndRemoveUntil(Routes.newSalesRoute, (route) => false),
icon: const Icon(Icons.arrow_back)),
title: const Text("Create Item"),
actions: [TextButton(onPressed: () {}, child: const Text("SAVE"))],
),
body: Padding(
padding: const EdgeInsets.all(10),
child: Form(
key: _formKey,
child: ListView(
children: [
TextFormField(
controller: nameController,
cursorColor: ColorManager.black,
decoration: const InputDecoration(hintText: "Name"),
validator: (value) {
if (value!.isEmpty || value.length < 5) {
return "name can't be less than 5 chars";
}
return null;
},
),
gapH24,
Text(
"Category",
style: TextStyle(color: ColorManager.grey),
),
SizedBox(
width: deviceSize.width,
child: DropdownButtonFormField<String>(
// value: "Categories",
hint: const Padding(
padding: EdgeInsets.only(left: 10),
child: Text('No Category'),
),
items: <String>['No Category', 'Create Category']
.map((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
onChanged: (_) {},
),
),
gapH24,
const Text(
"Sold by",
style: TextStyle(color: Colors.black),
),
gapH24,
Row(
children: [
Checkbox(
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(5.0))), // Rounded Checkbox
value: each,
onChanged: (inputValue) {
setState(() {
each = !each;
});
},
),
gapW4,
const Text(
"Each",
style: TextStyle(fontWeight: FontWeight.bold),
),
],
),
gapH24,
Row(
children: [
Checkbox(
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(5.0))), // Rounded Checkbox
value: !each,
onChanged: (inputValue) {
setState(() {
each = !each;
});
},
),
gapW4,
const Text(
"Weight",
style: TextStyle(fontWeight: FontWeight.bold),
),
],
),
TextFormField(
controller: priceController,
decoration: InputDecoration(
hintText: "Price",
hintStyle: TextStyle(color: ColorManager.grey)),
validator: (value) {
if (value!.isEmpty) {
return "price can,t be empty";
}
return null;
},
),
gapH4,
Text(
"leave the field blank to indicate price upon sale",
style: TextStyle(color: ColorManager.grey),
),
gapH20,
Text(
"Cost",
style: TextStyle(color: ColorManager.grey),
),
TextFormField(
controller: costController,
decoration: InputDecoration(
hintText: "cost",
hintStyle: TextStyle(color: ColorManager.black)),
validator: (value) {
if (value!.isEmpty) {
return "cost can't be empty";
}
return null;
},
),
gapH20,
Text(
"SKU",
style: TextStyle(color: ColorManager.grey),
),
TextFormField(
controller: skuController,
decoration: InputDecoration(
hintText: "Sku",
hintStyle: TextStyle(color: ColorManager.black)),
validator: (value) {
if (value!.isEmpty) {
return "Sku can't be empty";
}
return null;
},
),
gapH30,
TextFormField(
controller: barcodeController,
decoration: InputDecoration(
hintText: "Barcode",
hintStyle: TextStyle(color: ColorManager.grey)),
validator: (value) {
if (value!.isEmpty) {
return "Barcode can't be empty";
}
return null;
},
),
gapH30,
// Divider(thickness: 1,color: ColorManager.black,),
Text(
"Inventory",
style: TextStyle(
color: ColorManager.green,
fontSize: 15,
fontWeight: FontWeight.bold),
),
// ListTile(
// title: Text("TrackStock",style: TextStyle(color: ColorManager.green,fontSize: 15,fontWeight: FontWeight.bold)),
// trailing: Switch(value: switchValue, onChanged: (bool value) {
// setState(() {
// switchValue=!switchValue;
// });
// },),
// ),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text("TrackStock",
style: TextStyle(
color: ColorManager.grey,
fontSize: 15,
fontWeight: FontWeight.bold)),
Switch(
value: switchValue,
onChanged: (bool value) {
setState(() {
switchValue = !switchValue;
});
},
),
],
),
gapH10,
if (switchValue)
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"in stock",
style:
TextStyle(color: ColorManager.grey, fontSize: 15),
),
TextFormField(
keyboardType: TextInputType.number,
controller: inStockController,
decoration: const InputDecoration(hintText: "0"),
validator: (value) {
if (value!.isEmpty) {
return "value can't be empty";
}
return null;
},
)
],
),
gapH20,
Text(
"Representation in POS",
style: TextStyle(
color: ColorManager.green,
fontSize: 15,
fontWeight: FontWeight.bold),
),
gapH15,
Row(
children: [
Checkbox(
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(5.0))), // Rounded Checkbox
value: isColor,
onChanged: (inputValue) {
setState(() {
if (!isColor) {
isColor = !isColor;
}
});
},
),
gapW4,
const Text(
"Color and Shape",
style: TextStyle(fontWeight: FontWeight.bold),
),
],
),
gapH10,
Row(
children: [
Checkbox(
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(5.0))), // Rounded Checkbox
value: !isColor,
onChanged: (inputValue) {
setState(() {
if (isColor) {
isColor = !isColor;
}
});
},
),
gapW4,
const Text(
"Image",
style: TextStyle(fontWeight: FontWeight.bold),
),
],
),
isColor
? GridView.builder(
physics:
const NeverScrollableScrollPhysics(), // to disable GridView's scrolling
shrinkWrap: true, // You won't see infinite size error
gridDelegate:
const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 4,
crossAxisSpacing: 5.0,
mainAxisSpacing: 5.0,
),
itemCount: containers().length,
itemBuilder: (BuildContext context, int index) {
return containers()[index];
},
)
: Padding(
padding: const EdgeInsets.all(10),
child: Row(
children: [
Expanded(
flex: 1,
child: base64File == ""
? const Icon(Icons.person)
: Container(
decoration: BoxDecoration(
borderRadius:
BorderRadius.circular(5)),
child: Image.memory(
base64.decode(base64File)))),
gapW4,
Expanded(
flex: 2,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
TextButton(
onPressed: () =>
pickImage(ImageSource.camera),
child: Row(
children: [
Icon(
Icons.camera_alt,
color: ColorManager.black,
),
gapW8,
Text(
"Take a photo",
style: TextStyle(
color: ColorManager.black,
),
)
],
),
),
const Divider(
thickness: 1,
color: Colors.grey,
),
TextButton(
onPressed: () =>
pickImage(ImageSource.gallery),
child: Row(
children: [
Icon(Icons.camera_alt,
color: ColorManager.black),
gapW8,
Text(
"Choose from gallery",
style: TextStyle(
color: ColorManager.black,
),
)
],
),
)
],
),
)
],
),
)
],
),
),
),
floatingActionButton: FloatingActionButton(
child: const Icon(Icons.save,color: Colors.white,),
onPressed: () async {
bool isValid = _formKey.currentState!.validate();
if (isValid) {
FocusScope.of(context).unfocus();
ItemModel? item=await bloc.checkItem(nameController.text);
if(item!=null){
displayMessage("this item was inserted before", context);
}else{
int? res=await bloc.saveItem(ItemModel(
nameController.text,
priceController.text,
costController.text,
skuController.text,
barcodeController.text));
if(res!=null){
displayMessage("an item was inserted successfully", context);
Navigator.of(context).pushAndRemoveUntil(MaterialPageRoute(builder: (context)=>const NewSales()), (route) => false);
}
}
}
},
),
);
}
),
);
}
}
this is the SaleCubit
class SalesCubit extends Cubit<SalesState> {
SalesCubit() : super(SalesInitial());
bool isSearch=false;
ItemDBHelper db=ItemDBHelper();
List<ItemModel> items=[];
List<ItemModel> filteredItems=[];
String bsResult='Unknown'; //barcode search result
void toggleSearch(){
isSearch=!isSearch;
emit(IsSearch());
}
void setBarcodeResult(String value){
bsResult=value;
emit(SearchDone());
}
void filterItems(String query){
// emit(Searching());
query.isEmpty?
filteredItems=items:
filteredItems=items.where((item) => item.name.toLowerCase().contains(query.toLowerCase())).toList();
emit(SearchDone());
}
Future<List<ItemModel>?> getAllItems()async{
try{
emit(IsLoading());
items=await db.getAllItems();
filteredItems=items;
print(items);
return items;
}finally{
emit(Loaded());
}
}
Future<void> deleteItem(String name)async{
await db.deleteItem(name);
emit(SearchDone());
}
}
this is the SalesState
part of 'sales_cubit.dart';
#immutable
abstract class SalesState {}
class SalesInitial extends SalesState {}
class IsSearch extends SalesState {}
class IsLoading extends SalesState {}
class Loaded extends SalesState {}
class Searching extends SalesState {}
class SearchDone extends SalesState {}

Dynamic DropDownFormField returns null on Submit Button

I have created a page where user can input their exam result which are subject and grade.
On the page, user need to click the add subject button to add another subject depending on how many subject they have. User also can remove subject by clicking the remove subject button.
The problem is only TextFormField value submitted. How to get the data for DropDownFormField if the form created dynamically?
I have tried the read the data using the onChanged function of the drop down and yes the data was stored to the variable gradeController but it returns null when I submit the data.
This is the model
class SubjectGrade {
final String? name;
final String? grade;
SubjectGrade(this.name, this.grade);
#override
String toString() {
return 'SPM: name = $name, grade = $grade';
}
}
This is the form
import 'package:flutter/material.dart';
import 'package:testing_app/models/education_model.dart';
class EducationBackgroundForm extends StatefulWidget {
const EducationBackgroundForm({Key? key}) : super(key: key);
#override
_EducationBackgroundFormState createState() =>
_EducationBackgroundFormState();
}
class _EducationBackgroundFormState extends State<EducationBackgroundForm> {
final nameTECs = <TextEditingController>[];
final gradeTECs = <String?>[];
final forms = <Form>[];
Form createForm() {
TextEditingController nameController = TextEditingController();
String? gradeController;
nameTECs.add(nameController);
gradeTECs.add(gradeController);
final grades = ['A+', 'A', 'A-', 'B+', 'B', 'C+', 'C', 'D', 'E', 'G'];
DropdownMenuItem<String> buildMenuItem(String item) => DropdownMenuItem(
value: item,
child: Text(item),
);
return Form(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Row(
children: <Widget>[
Expanded(
flex: 2,
child: Column(
children: <Widget>[
TextFormField(
controller: nameController,
decoration: InputDecoration(
hintText: 'Subject Name',
labelText: 'Subject ${forms.length + 1}',
border: const OutlineInputBorder(),
contentPadding:
const EdgeInsets.only(left: 8, right: 8),
),
keyboardType: TextInputType.text,
textInputAction: TextInputAction.done,
),
],
),
),
const SizedBox(width: 5),
Expanded(
flex: 1,
child: Column(
children: <Widget>[
DropdownButtonHideUnderline(
child: DropdownButtonFormField(
value: gradeController,
isExpanded: true,
iconSize: 36,
icon: const Icon(Icons.arrow_drop_down,
color: Colors.black),
items: grades.map(buildMenuItem).toList(),
onChanged: (String? value) {
setState(() {
gradeController = value;
});
},
hint: const Text("Grade"),
decoration: const InputDecoration(
border: OutlineInputBorder(),
contentPadding: EdgeInsets.only(left: 8),
),
),
)
],
)),
],
),
const SizedBox(height: 10)
],
),
);
}
#override
void initState() {
super.initState();
forms.add(createForm());
}
saveSPMResultToFirebase() {
List<SubjectGrade> entries = [];
for (int i = 0; i < forms.length; i++) {
final name = nameTECs[i].text;
final grade = gradeTECs[i].toString();
entries.add(SubjectGrade(name, grade));
}
debugPrint(entries.toString());
//Navigator.pop(context, entries);
}
#override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
const Text("SPM Result", style: TextStyle(fontSize: 18)),
const SizedBox(height: 20),
Expanded(
child: ListView.builder(
itemCount: forms.length,
itemBuilder: (BuildContext context, int index) {
return forms[index];
},
),
),
const SizedBox(height: 20),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Expanded(
child: SizedBox(
width: double.infinity,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.all(14),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8))),
onPressed: () => setState(() {
forms.add(createForm());
}),
child: const Text(
'Add Subject',
style: TextStyle(
fontSize: 16,
),
),
),
),
),
const SizedBox(width: 5),
Expanded(
child: SizedBox(
width: double.infinity,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.all(14),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8))),
onPressed: () => setState(() {
if (forms.length > 1) {
forms.removeAt(forms.length - 1);
}
}),
child: const Text(
'Remove Subject',
style: TextStyle(
fontSize: 16,
),
),
),
),
),
],
),
const SizedBox(height: 10),
SizedBox(
width: double.infinity,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.all(14),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8))),
onPressed: () {
saveSPMResultToFirebase();
},
child: const Text(
'Update',
style: TextStyle(
fontSize: 16,
),
),
),
),
],
);
}
}
When I submit the form, the debug output I get from the submit function for grade is null.
Output:
[SPM: name = English, grade = null]
You should add value of DropDownButton in onChanged method not at top of create form.
change your code to this:
First Delete gradeTECs.add(gradeController); line from top of createForm().
Form createForm() {
TextEditingController nameController = TextEditingController();
String? gradeController;
nameTECs.add(nameController);
// gradeTECs.add(gradeController); <==== DELETE THIS LINE.
Add gradeTECs.add(gradeontroller); in onChanged method of DropdownButtonFormField
DropdownButtonHideUnderline(
child: DropdownButtonFormField(
value: gradeController,
isExpanded: true,
iconSize: 36,
icon: const Icon(Icons.arrow_drop_down,
color: Colors.black),
items: grades.map(buildMenuItem).toList(),
onChanged: (String? value) {
setState(() {
gradeController = value;
gradeTECs.add(gradeController); <=== ADD HERE ==>
});
},
hint: const Text("Grade"),
decoration: const InputDecoration(
border: OutlineInputBorder(),
contentPadding: EdgeInsets.only(left: 8),
),
),
),

Radio Button while using in List builder

I faced problem of separating value of radio button . As I use multiple radio buttons in multiple list that i get from APi. so every time , when i select one radio button ,it selects all radio button of this type in all list. for example: radio 1 = check , radio 2 = unchecked in list 1 and list 2. i select radio 1 of list 1 but both radio 1 of list 1 and list 2 selected.
import 'dart:convert';
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:lottie/lottie.dart';
import 'package:http/http.dart' as http;
import 'package:progress_dialog/progress_dialog.dart';
import 'package:project40/Constants/APIConstants.dart';
import 'package:project40/Constants/styleConstant.dart';
import 'package:project40/screens/home_screen.dart';
import 'package:rflutter_alert/rflutter_alert.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:project40/api/add_filter_api.dart';
import 'package:project40/provider/add_post_provider.dart';
import 'package:provider/provider.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:project40/Constants/globals.dart' as globals;
class FilterScreen extends StatefulWidget {
#override
_FilterScreenState createState() => _FilterScreenState();
}
class _FilterScreenState extends State<FilterScreen> {
var jsonData;
//String filterVariable;
int school_everyone = 0;
bool all_Feed = true;
AddPostProvider _addPostProvider;
int length = 0;
int v = 0;
Future mySchools() async {
print("test");
//loading dialog appears
ProgressDialog pr;
pr = new ProgressDialog(context, showLogs: true);
pr.style(
progressWidget: Container(
width: 50,
child: Lottie.asset("assets/json/360-loader.json"),
),
message: 'Please wait...');
pr.show();
//api link
String url = baseURL + mySchoolURL;
//getting user token
SharedPreferences prefs = await SharedPreferences.getInstance();
String token = prefs.getString("token");
print(token);
//create post request
http.Response response = await http.get(url, headers: {
"Content-Type": "application/json",
'Authorization': 'Bearer $token',
}).catchError((e) => print(e));
print('successs');
pr.hide();
if (response == null) {
//appear dialog if any error will be occured
Alert(
context: context,
title: "",
type: AlertType.none,
desc: "Something went wrong. Please try again",
buttons: [
DialogButton(
child: Text(
"OK",
style: TextStyle(color: Colors.white, fontSize: 20),
),
onPressed: () {
Navigator.pop(context);
pr.hide();
},
width: 120,
)
],
).show();
} else {
jsonData = jsonDecode(response.body);
if (jsonData["status_code"] == 200) {
print(jsonData);
// if (all_Feed == true) {
// filterVariable = "All School";
// }
// print(filterVariable);
pr.hide();
//store the no of institutions
length = jsonData["data"].length;
setState(() {});
} else {
pr.hide();
//if error occured
Alert(
context: context,
type: AlertType.none,
title: "",
desc: jsonData["message"],
buttons: [
DialogButton(
child: Text(
"OK",
style: TextStyle(color: Colors.white, fontSize: 20),
),
onPressed: () {
Navigator.pop(context);
pr.hide();
},
width: 120,
)
],
).show();
}
}
return jsonDecode(response.body);
}
#override
void initState() {
super.initState();
mySchools();
if (all_Feed == true) {
school_everyone = 0;
}
if (school_everyone == 1) {
all_Feed = false;
}
// if (all_Feed == false) {
// setState(() {
// selectedRadio(2);
// });
// }
// if (school_everyone == 1) {
// setState(() {
// all_school = 0;
// });
// }
}
void selectedRadio(int value) {
setState(() {
all_Feed = false;
school_everyone = value;
});
}
#override
Widget build(BuildContext context) {
_addPostProvider = Provider.of<AddPostProvider>(context, listen: false);
return Material(
child: Scaffold(
backgroundColor: Colors.grey,
body: Stack(
//alignment: AlignmentDirectional.topCenter,
children: [
Container(
padding: EdgeInsets.only(top: 5),
decoration: BoxDecoration(
//borderRadius: BorderRadius.circular(50),
),
child: Padding(
padding: const EdgeInsets.only(top: 45),
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(15),
topRight: Radius.circular(15),
),
color: Colors.white,
),
child: Column(
children: [
SizedBox(
height: 20,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
GestureDetector(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Icon(Icons.arrow_back),
),
onTap: () {
Navigator.pop(context);
},
),
Text(
"Feed Filter",
textAlign: TextAlign.center,
style: TextStyle(
fontFamily: "Roboto",
fontSize: 20,
fontWeight: FontWeight.bold),
),
Container(width: 32.0),
],
),
Divider(
thickness: 1,
),
SizedBox(
height: 10,
),
Padding(
padding: const EdgeInsets.only(left: 20),
child: GestureDetector(
onTap: () {
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => HomeScreen()));
},
child: allFilter(
Checkbox(
value: all_Feed,
activeColor: Colors.black,
onChanged: (value) {
setState(() {
all_Feed = value;
if (all_Feed == true) {
school_everyone = 0;
} else {
school_everyone = 1;
}
});
}),
Text(
"All school",
style: DayMoodRobotoStyle.heading5c,
)),
),
),
Expanded(
child: ListView.builder(
itemCount: length,
itemBuilder: (context, index) {
return SingleChildScrollView(
child: Container(
child: schoolUseage(
jsonData["data"][index]["institution"]
["name"] ??
"",
jsonData["data"][index]["institution"]
["none"] ??
"",
jsonData["data"][index]["institution"]
["_id"] ??
"",
jsonData["data"][index]["year"]["year"] ??
"",
jsonData["data"][index]["year"]["_id"] ??
"",
jsonData["data"][index]["program"] == null
? ""
: jsonData["data"][index]["program"]
["title"],
jsonData["data"][index]["program"] == null
? ""
: jsonData["data"][index]["program"]
["_id"],
index),
),
);
}),
),
InkWell(
onTap: () async {
// var response =
// await GetFilterPostAPI().getFilterPostApi(
// ids: globals.filterVariable,
// );
// print('add filter response$response');
// if (response['status_code'] == 200) {
// _addPostProvider.addPostProgress = false;
Navigator.pop(context);
Fluttertoast.showToast(
msg: 'Filter Add Successfully..');
// _addPostProvider.addPostProgress = false;
// } else {
// Fluttertoast.showToast(msg: response['message']);
// _addPostProvider.addPostProgress = false;
// }
},
hoverColor: Colors.transparent,
splashColor: Colors.transparent,
highlightColor: Colors.transparent,
child: Container(
alignment: Alignment.center,
width: double.infinity,
height: 55.0,
margin: EdgeInsets.symmetric(
horizontal: 20,
),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(28.0),
color: const Color(0xff0188ba),
boxShadow: [
BoxShadow(
color: const Color(0x333F51B5).withOpacity(0.2),
offset: Offset(0, 20),
blurRadius: 20,
),
],
),
child: Text(
'Filter',
style: DayMoodRobotoStyle.heading5,
textAlign: TextAlign.center,
),
),
),
SizedBox(
height: 20,
),
],
),
),
),
),
],
),
),
);
}
Widget schoolInfo(Radio icon, Expanded schoolname) {
return Row(
children: [icon, schoolname],
);
}
Widget allFilter(Checkbox icon, Text schoolname) {
return Row(
children: [icon, schoolname],
);
}
Widget schoolUseage(
String schooolName,
String school_id,
String _id,
String classOf,
String classof_id,
String department,
String department_id,
int index) {
String s1 = index.toString();
String s2 = school_everyone.toString();
String s = s1 + s2;
v = int.parse(s);
return Column(
children: [
Align(
alignment: Alignment.topLeft,
child: Padding(
padding: const EdgeInsets.only(left: 20),
child: Text(
schooolName,
style: TextStyle(
color: all_Feed == true ? Colors.grey : Colors.blue,
fontSize: 17,
fontFamily: "Ubuntu",
letterSpacing: 0.17,
fontWeight: FontWeight.w700),
),
),
),
SizedBox(
height: 5,
),
Padding(
padding: const EdgeInsets.only(left: 20),
child: all_Feed == true
? IgnorePointer(
ignoring: true,
child: schoolInfo(
Radio(
activeColor: Colors.black,
value: null,
groupValue: index,
onChanged: (value) {
selectedRadio(value);
globals.filterVariable =
"all_" + school_id + "program_" + _id;
}),
Expanded(
child: Text(
"Everyone",
style: TextStyle(
fontFamily: 'Ubuntu',
fontSize: 15,
color: Colors.grey,
letterSpacing: 0.17,
fontWeight: FontWeight.w700),
),
)),
)
: schoolInfo(
Radio(
activeColor: Colors.black,
value: 1,
groupValue: v,
onChanged: (value) {
setState(() {
// String s1 = index.toString();
// String s2 = value.toString();
// String s = s1 + s2;
// v = int.parse(s);
selectedRadio(value);
globals.filterVariable = "all_$_id";
});
}),
Expanded(
child: Text(
"Everyone",
style: DayMoodRobotoStyle.heading5c,
),
)),
),
Padding(
padding: const EdgeInsets.only(left: 20),
child: all_Feed == true
? IgnorePointer(
child: schoolInfo(
Radio(
activeColor: Colors.black,
value: 2,
groupValue: school_everyone,
onChanged: (value) {
selectedRadio(value);
}),
Expanded(
child: Text(
"None",
style: TextStyle(
fontFamily: 'Ubuntu',
fontSize: 15,
color: Colors.grey,
letterSpacing: 0.17,
fontWeight: FontWeight.w700),
),
)),
)
: schoolInfo(
Radio(
activeColor: Colors.black,
value: 2,
groupValue: v,
onChanged: (value) {
setState(() {
// String s1 = index.toString();
// String s2 = value.toString();
// String s = s1 + s2;
// v = int.parse(s);
selectedRadio(value);
globals.filterVariable = "none_" + _id;
});
}),
Expanded(
child: Text(
"None",
style: DayMoodRobotoStyle.heading5c,
),
)),
),
Padding(
padding: const EdgeInsets.only(left: 20, right: 20),
child: all_Feed == true
? IgnorePointer(
child: schoolInfo(
Radio(
activeColor: Colors.black,
value: 2,
groupValue: school_everyone,
onChanged: (value) {
selectedRadio(value);
}),
Expanded(
child: Text(
department + " Only",
style: TextStyle(
fontFamily: 'Ubuntu',
fontSize: 15,
color: Colors.grey,
letterSpacing: 0.17,
fontWeight: FontWeight.w700),
maxLines: 2,
),
),
),
)
: schoolInfo(
Radio(
activeColor: Colors.black,
value: 3,
groupValue: v,
onChanged: (value) {
setState(() {
// String s1 = index.toString();
// String s2 = value.toString();
// String s = s2 + s1;
// v = int.parse(s);
selectedRadio(value);
globals.filterVariable = "program_" + _id;
});
}),
Expanded(
child: Text(
department + " Only",
style: DayMoodRobotoStyle.heading5c,
maxLines: 2,
),
),
),
),
Padding(
padding: const EdgeInsets.only(left: 20),
child: all_Feed == true
? IgnorePointer(
child: schoolInfo(
Radio(
activeColor: Colors.black,
value: classof_id,
groupValue: school_id,
onChanged: (value) {
selectedRadio(value);
}),
Expanded(
child: Text(
"Class of " + classOf + " Only",
style: TextStyle(
fontFamily: 'Ubuntu',
fontSize: 15,
color: Colors.grey,
letterSpacing: 0.17,
fontWeight: FontWeight.w700),
),
)),
)
: schoolInfo(
Radio(
activeColor: Colors.black,
value: 4,
groupValue: v,
onChanged: (value) {
setState(() {
// String s1 = index.toString();
// String s2 = value.toString();
// String s = s2 + s1;
// v = int.parse(s);
selectedRadio(value);
globals.filterVariable = "year_" + _id;
//classOf + "_" + school_id;
});
}),
Expanded(
child: Text(
"Class of " + classOf + " Only",
style: DayMoodRobotoStyle.heading5c,
),
)),
),
Padding(
padding: const EdgeInsets.only(left: 20),
child: all_Feed == true
? IgnorePointer(
child: schoolInfo(
Radio(
activeColor: Colors.black,
value: all_Feed == true ? 0 : department_id,
groupValue: school_id,
onChanged: (value) {
selectedRadio(value);
}),
Expanded(
child: Text(
department + " - " + classOf,
style: TextStyle(
fontFamily: 'Ubuntu',
fontSize: 15,
color: Colors.grey,
letterSpacing: 0.17,
fontWeight: FontWeight.w700),
),
)),
)
: schoolInfo(
Radio(
activeColor: Colors.black,
value: 5,
groupValue: v,
onChanged: (value) {
setState(() {
// String s1 = index.toString();
// String s2 = value.toString();
// String s = s2 + s1;
// v = int.parse(s);
selectedRadio(value);
globals.filterVariable = "programyear_" + _id;
// department + classOf + "_" + school_id;
});
}),
Expanded(
child: Text(
department + " - " + classOf,
style: DayMoodRobotoStyle.heading5c,
),
)),
),
SizedBox(
height: 20,
),
],
);
}
}
Here is the minimum implementation of 2Radio button groups.
class _TestState extends State<Test> {
int group1Value;
int group2Value;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Radio"),
),
body: Column(
children: [
//Let suppose this is group 1
Row(
children: [
Radio(
value: 0,
groupValue: group1Value,
onChanged: (value) {
setState(() {
group1Value = value;
});
},
),
Expanded(child: Text("Radio1")),
],
),
Row(
children: [
Radio(
value: 1,
groupValue: group1Value,
onChanged: (value) {
setState(() {
group1Value = value;
});
},
),
Expanded(child: Text("Radio2")),
],
),
Row(
children: [
Radio(
value: 2,
groupValue: group1Value,
onChanged: (value) {
setState(() {
group1Value = value;
});
},
),
Expanded(child: Text("Radio3")),
],
),
SizedBox(height: 20),
Text(
"Second Group",
style: Theme.of(context).textTheme.subtitle1.copyWith(
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 20),
//suppose this is group 2
Row(
children: [
Radio(
value: 0,
groupValue: group2Value,
onChanged: (value) {
setState(() {
group2Value = value;
});
},
),
Expanded(child: Text("Radio1")),
],
),
Row(
children: [
Radio(
value: 1,
groupValue: group2Value,
onChanged: (value) {
setState(() {
group2Value = value;
});
},
),
Expanded(child: Text("Radio2")),
],
),
Row(
children: [
Radio(
value: 2,
groupValue: group2Value,
onChanged: (value) {
setState(() {
group2Value = value;
});
},
),
Expanded(child: Text("Radio3")),
],
),
],
),
);
}
}
Here are the results