How can i print checkbox value on Text() Widget using Flutter - flutter

Is there a way to print checkbox value in a Text widget Eg. I make two checkbox which have a value of POD and Prepaid i would like to print out the selected checkbox value on Text() Widget.
Code:-
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
children: [
Checkbox(
value: prepaidCheckBoxValue,
shape: const CircleBorder(),
checkColor: Colors.white,
onChanged: (value) {
prepaidCheckBoxValue = !prepaidCheckBoxValue;
//print(prepaidCheckBoxValue);
setState(() {});
},
),
const Text(
'Prepaid',
style: TextStyle(
fontSize: 20.0,
),
),
const SizedBox(
width: 30.0,
),
Checkbox(
value: podCheckBoxValue,
shape: const CircleBorder(),
checkColor: Colors.white,
onChanged: (value) {
podCheckBoxValue = !podCheckBoxValue;
setState(() {});
//print(value);
},
),
const Text(
'Pay on Delivery',
style: TextStyle(
fontSize: 20.0,
),
),
],
),
),

My recommendation
create a enum for payment methods
enum PaymentTypes {
prepaid,
pay_on_delivery,
}
create a local variable to store selected payment method in your state class
PaymentTypes selectedPaymentType;
set the selected payment method on checkbox onChange method
Checkbox(
//prepaid checkbox
...
onChanged: (value) {
podCheckBoxValue = !podCheckBoxValue;
setState(() {
selectedPaymentType = PaymentTypes.prepaid;
});
//print(value);
},
),
Checkbox(
//pay on delivery checkbox
...
onChanged: (value) {
podCheckBoxValue = !podCheckBoxValue;
setState(() {
selectedPaymentType = PaymentTypes.pay_on_delivery;
});
//print(value);
},
),
use selectedPaymentType value on Textbox
const Text(
describeEnum(selectedPaymentType).replaceAll(RegExp('_'), ' ')
)
Or you can just use a string to store the checkbox value without enums
String selectedPaymentType;
onChanged: (value) {
podCheckBoxValue = !podCheckBoxValue;
setState(() {
selectedPaymentType = 'Pay on delivery';
});
//print(value);
},
),
const Text(
selectedPaymentType
)

Related

StateNotifier not updating inside the data function of FutureProvider in Flutter Riverpod

The StateNotifier with the gender does not update as the dropdown choice changes. I have these providers at the beginning of the file:
class GenderController extends StateNotifier<String>{
GenderController(String state) : super(state);
}
final profileProvider = FutureProvider.autoDispose((ref) {
final details = ref.watch(authToken);
var data = API().staffProfile(token: details['token'], staffID: details['ID']);
return data;
});
final gender = StateNotifierProvider.autoDispose((ref) => GenderController(""));
And this is what the build method looks like in a ConsumerWidget:
Widget build(BuildContext context, WidgetRef ref) {
var dropdownValue = ref.watch(gender);
final details = ref.watch(profileProvider);
return details.when(
data: (data){
dropdownValue = data['gender'];
// show the form with the info
return Padding(
padding: const EdgeInsets.all(8.0),
child: Form(
key: formKey,
child: Column(
children: [
DropdownButton2(
isExpanded: true,
underline: Container(
color: kDarkGrey,
height: 1.0,
),
buttonPadding: const EdgeInsets.symmetric(vertical: 10.0),
hint: const CustomText(
text: "Gender",
fontSize: 16.0,
color: kBlack,
),
items: genders
.map((item) => DropdownMenuItem<String>(
value: item,
child: Text(
item,
style: const TextStyle(
fontSize: 16,
color: kBlack,
),
overflow: TextOverflow.ellipsis,
),
))
.toList(),
value: dropdownValue == "" ? null : dropdownValue.toString(),
onChanged: (value) {
ref.watch(gender.notifier).state = value!;
}
),
],
)
),
);
},
error: (err, _){
debugPrint(_.toString());
return const Center(
child: CustomText(
text: "Error getting profile",
),
);
},
loading: () => Center(
child: CircularProgressIndicator(
color: kPrimary,
),
)
);
}
I have also tried making the data type of the dropdownValue to be final and then assigning the data to it as ref.watch(gender.notifier).state = data['gender']; but that resulted in a "At least listener of the StateNotifier Instance of 'GenderController' threw an exception when the notifier tried to update its state." error. Please help.
In callbacks, you must call ref.read
ref.read(gender.notifier).state = data['gender'];
I figured it out. I initialised the dropdown before calling the details.when like this:
DropdownButton2 dropdown = DropdownButton2(
isExpanded: true,
underline: Container(
color: kDarkGrey,
height: 1.0,
),
buttonPadding: const EdgeInsets.symmetric(vertical: 10.0),
hint: const CustomText(
text: "Gender",
fontSize: 16.0,
color: kBlack,
),
items: genders
.map((item) => DropdownMenuItem<String>(
value: item,
child: Text(
item,
style: const TextStyle(
fontSize: 16,
color: kBlack,
),
overflow: TextOverflow.ellipsis,
),
))
.toList(),
value: dropdownValue == "" ? null : dropdownValue.toString(),
onChanged: (value) {
ref.read(gender.notifier).state = value!;
}
);
And then I updated the StateNotifier after the data was returned in the FutureProvider like so:
final profileProvider = FutureProvider.autoDispose((ref) async {
final details = ref.watch(authToken);
var data = await API().staffProfile(token: details['token'], staffID: details['ID']);
ref.read(gender.notifier).state = data['gender'];
return data;
});
Everything works fine now, and as it should.

Flutter dropdown value if not selected, then assign the initial value

I have a DropDownButtonFormField I need to check this. If the dropdown value is not selected by the user then assign the initial value when submitting.
Custom DropDown
Container myDropDownContainer(String initialVal, List<String> listItems,
String text, Function myFunc, Function validate) {
return Container(
margin: const EdgeInsets.all(8),
child: Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.start,
children: [
SizedBox(
width: 120,
child: Text(
text,
style: kTextStyle,
),
),
const SizedBox(
width: 20,
),
Expanded(
child: Container(
height: 50,
decoration: BoxDecoration(
color: Colors.orangeAccent,
borderRadius: BorderRadius.circular(5)),
child: DropdownButtonFormField<String>(
autovalidateMode: AutovalidateMode.always,
//menuMaxHeight: 300,
validator: (value) {
if(value!.isEmpty) {
return "485s4a8sd4as85";
}
} ,
decoration: const InputDecoration(border: InputBorder.none),
isExpanded: true,
onTap: () => myFunc,
//borderRadius: BorderRadius.circular(5),
value: initialVal,
icon: const Icon(
Icons.arrow_downward,
color: Colors.black38,
),
iconSize: 24,
elevation: 16,
dropdownColor: Colors.deepOrange,
style: kTextStyle.copyWith(color: Colors.black),
onChanged: (val) => myFunc(val),
items: listItems.map<DropdownMenuItem<String>>((String? val) {
return DropdownMenuItem(
//TODO: Set default values
value: val,
child: Text(
val,
style: kTextStyle.copyWith(color: Colors.black),
),
);
}).toList(),
),
),
)
],
),
);
}
This is my onChanged property that assigns the selected value by the user. I added some explanations about what I am trying to do.
String _valueCinsiyet = "Diğer"; // initial value
void onChangedCinsiyet(String? newVal) {
setState(() {
if(newVal==null) {
_formData.setCinsiyet(_valueCinsiyet);
/*
'if newVal is null' means that if the value is not selected by the user
then set the initialValue( _valueCinsiyet)
*/
} else {
/*
if newVal is not null then assign the newVal( which means the selected value)
into my initialValue, then set the data to use it on different pages. What is missing?
*/
_valueCinsiyet = newVal;
_formData.setCinsiyet(_valueCinsiyet);
}
});
}
You can use nullable data to track DropdownButtonFormField changes. Being nullable you can check if it is null or not, no need to anything extra on onChanged: just assign new value usual way.
On state before build method: String? value; // value to keep track
child: DropdownButtonFormField<String>(
value: value,
onChanged: (val) {
setState(() {
value = val;
});
},
Now onSaved/submit button you can pass value by checking null, simple way is
value?? "default Value". In your case, it is value??Diğer

How set form validation in widget flutter

I'm working on flutter project .I have a revision form validator that is not working as expected. When I leave the TextFormField empty the validator doesn't show me anything. I want to stay on the revision form until I enter the values.
thanks in advance
my code :
class Revision extends StatefulWidget {
}
class _RevisionState extends State<Revision> with TickerProviderStateMixin {
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
RevisionApi revisionApi = RevisionApi();
TextEditingController _Kilometrage_revisionController =
TextEditingController();
_showAddDialog() async {
await showDialog(
context: context,
builder: (context) => AlertDialog(
backgroundColor: Colors.white,
title: Text("Ajouter un évènement"),
content: StatefulBuilder(builder: (
BuildContext context,
StateSetter setState,
) {
return SingleChildScrollView(
child: Form(
key: _formKey,
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(children: [
Expanded(
child: DropdownButtonFormField(
decoration: InputDecoration(
hoverColor: Colors.white,
//contentPadding: EdgeInsets.only(left: 10, right: 15, top: 15),
labelText: 'Type',
alignLabelWithHint: true,
labelStyle: TextStyle(
color: kPrimaryColor,
),
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.grey),
),
),
dropdownColor: Colors.white,
value: status,
items: <DropdownMenuItem>[
DropdownMenuItem(
// value: 'videnge',
value: 0,
child: InkWell(
child: Text('videnge'),
hoverColor: Colors.indigo,
),
),
DropdownMenuItem(
// value: 'visite technique',
value: 1,
child: Text('visite technique'),
),
DropdownMenuItem(
// value: 'assurance véhicule',
value: 2,
child: Text('assurance véhicule'),
),
DropdownMenuItem(
// value: 'autre',
value: 3,
child: Text('autre'),
),
],
onChanged: (value) {
setState(() {
status = value;
});
},
)),
]),
if (status == 1) visiTechniqueDropdown(),
]),
));
}),
actions: <Widget>[
TextButton(
child: Text(
"Enregistrer",
style: TextStyle(
color: Colors.red, fontWeight: FontWeight.bold),
),
onPressed: () {
if (status == null) return;
setState(() {
if (_events[_controller.selectedDay] != null) {
_events[_controller.selectedDay].add(status);
} else {
_events[_controller.selectedDay] = [status];
}
prefs.setString(
"events", json.encode(encodeMap(_events)));
status;
setRevision();
_KilometrageController.clear();
_eventController.clear();
_EmplacementController.clear();
_DateController.clear();
_repeat_revisionController.clear();
_revision_agenceController.clear();
_Kilometrage_revisionController.clear();
Navigator.of(context).pop();
// Navigator.pop(context);
});
},
),
new TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: const Text('Retour'),
),
],
));
}
void setRevision() async {
print("hello");
if (_formKey.currentState.validate()) {
String kilometrage_pour_vidange = _KilometrageController.text;
String revision_type = status.toString();
String revision_title = _eventController.text;
String revision_location = _EmplacementController.text;
String revision_date = _DateController.text;
String repeat_revision = _repeat_revisionController.text;
String revision_agence = _revision_agenceController.text;
String kilometrage_revision = _Kilometrage_revisionController.text;
revisionApi
.setRevision(
revision_type,
revision_title,
revision_date,
revision_location,
kilometrage_pour_vidange,
repeat_revision,
revision_agence,
kilometrage_revision,
)
.then((data) {
if (data != null) {
Navigator.pop(context);
Navigator.of(context).pop();
Navigator.push(
context, MaterialPageRoute(builder: (context) => Revision()));
}
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text(data)));
}).catchError((error) {
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text(error.toString())));
});
setState(() {});
}
}
Widget visiTechniqueDropdown() {
return Column(mainAxisSize: MainAxisSize.min, children: [
Row(
children: [
Flexible(
child: TextFormField(
onFieldSubmitted: (_) => FocusScope.of(context).nextFocus(),
validator: (value) {
if (value.isEmpty) {
return 'Password is required';
}
return null;
},
controller: _DateController,
cursorColor: kPrimaryColor,
decoration: InputDecoration(
labelText: 'Date',
alignLabelWithHint: true,
labelStyle: TextStyle(
color: kPrimaryColor,
),
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.grey),
How i can set the validator correctly ?
This is for you. Thanks and enjoy
// Create a corresponding State class.
// This class holds data related to the form.
class MyFormState extends State<MyForm> {
// Create a global key that uniquely identifies the Form widget
// and allows validation of the form.
//
// Note: This is a GlobalKey<FormState>,
// not a GlobalKey<MyFormState>.
final _formKey = GlobalKey<FormState>();
#override
Widget build(BuildContext context) {
// Build a Form widget using the _formKey created above.
return Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
TextFormField(
// The validator receives the text that the user has entered.
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please enter some text';
}
return null;
},
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 16.0),
child: ElevatedButton(
onPressed: () {
// Validate returns true if the form is valid, or false otherwise.
if (_formKey.currentState!.validate()) {
// If the form is valid, display a snackbar. In the real world,
// you'd often call a server or save the information in a database.
// sendData();
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text('Processing Data')));
}
},
child: Text('Submit'),
),
),
],
),
);
}
}

How to check answers and change colors of radio buttons on right and wrong selection in flutter?

I am new in flutter app development. I have a issue in radio buttons. i have created a logic that works with flatButtons fine but i want to use this login with radio buttons. But my login gives me error that function name can't be assigned to function expressions.
Here is the image screenshot of error.
Material Button COde:
Widget choicebutton(String option, String k) {
return Padding(
padding: const EdgeInsets.all(5.0),
child: MaterialButton(
// materialTapTargetSize: MaterialTapTargetSize.padded,
onPressed: () => checkanswer(k),
child: Text(
mydata[1][i.toString()][k],
// textDirection:TextDirection.ltr,
//textAlign: TextAlign.left,
style: TextStyle(
fontFamily: "Alike",
fontSize: 16.0,
color: Colors.white,
),
// maxLines: 1,
),
// padding: EdgeInsets.fromLTRB(2.0, 2.0, 50.0, 50.0),
color: btncolor[k],
splashColor: Colors.indigo[700],
highlightColor: Colors.indigo[700],
minWidth: 320.0,
height: 90.0,
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(20.0)),
),
);
}
btncolor["a"] = Colors.indigo;
btncolor["b"] = Colors.indigo;
btncolor["c"] = Colors.indigo;
btncolor["d"] = Colors.indigo;
void checkanswer(String k) {
if (mydata[2][i.toString()] == mydata[1][i.toString()][k]) {
marks = marks + 1;
colortoshow = right;
} else {
colortoshow = wrong;
}
setState(() {
btncolor[k] = colortoshow;
canceltimer = true;
});
Timer(Duration(seconds: 1), nextquestion);
}
Widget Code:
Widget radioButton( k){
return RadioListTile(
value: 1,
groupValue: k ,
onChanged: (value){
checkanswer(k);
// btncolor[k];
},
title: Text(mydata[1][i.toString()][k],
style: TextStyle(
fontFamily: "Roboto",
fontSize: 18.0,
),
),
activeColor: btncolor[k],
);
}
Thanks in advance.
when passing functions as paramters you don't put the function name
For example
Widget radioBtn(){
return Radio(
value: null,
groupValue: null,
onChanged: (value){
},
);
}
If you however want to pass the function name, consider doing something like this
Widget radioBtn(){
return Radio(
value: null,
groupValue: null,
onChanged: whenRadioButtonChanges,
);
}
void whenRadioButtonChanges(value){
}
Hoep this helps you.

Checkbox form validation

How can I validate a checkbox in a Flutter Form? Every other validation works fine, but the checkbox doesn't show an Error.
Here is my code:
FormField(
validator: (value) {
if (value == false) {
return 'Required.';
}
},
builder: (FormFieldState<dynamic> field) {
return CheckboxListTile(
value: checkboxValue,
onChanged: (val) {
if (checkboxValue == false) {
setState(() {
checkboxValue = true;
});
} else if (checkboxValue == true) {
setState(() {
checkboxValue = false;
});
}
},
title: new Text(
'I agree.',
style: TextStyle(fontSize: 14.0),
),
controlAffinity: ListTileControlAffinity.leading,
activeColor: Colors.green,
);
},
),
A cleaner solution to this problem is to make a class that extends FormField<bool>
Here is how I accomplished this:
class CheckboxFormField extends FormField<bool> {
CheckboxFormField(
{Widget title,
FormFieldSetter<bool> onSaved,
FormFieldValidator<bool> validator,
bool initialValue = false,
bool autovalidate = false})
: super(
onSaved: onSaved,
validator: validator,
initialValue: initialValue,
builder: (FormFieldState<bool> state) {
return CheckboxListTile(
dense: state.hasError,
title: title,
value: state.value,
onChanged: state.didChange,
subtitle: state.hasError
? Builder(
builder: (BuildContext context) => Text(
state.errorText,
style: TextStyle(color: Theme.of(context).errorColor),
),
)
: null,
controlAffinity: ListTileControlAffinity.leading,
);
});
}
in case if you want to put your checkbox directly in your Form widget tree you can use solution provided below with FormField widget. Instead of using ListTile I used rows and columns as my form was requiring different layout.
FormField<bool>(
builder: (state) {
return Column(
children: <Widget>[
Row(
children: <Widget>[
Checkbox(
value: checkboxValue,
onChanged: (value) {
setState(() {
//save checkbox value to variable that store terms and notify form that state changed
checkboxValue = value;
state.didChange(value);
});
}),
Text('I accept terms'),
],
),
//display error in matching theme
Text(
state.errorText ?? '',
style: TextStyle(
color: Theme.of(context).errorColor,
),
)
],
);
},
//output from validation will be displayed in state.errorText (above)
validator: (value) {
if (!checkboxValue) {
return 'You need to accept terms';
} else {
return null;
}
},
),
You could try something like this :
CheckboxListTile(
value: checkboxValue,
onChanged: (val) {
setState(() => checkboxValue = val
},
subtitle: !checkboxValue
? Text(
'Required.',
style: TextStyle(color: Colors.red),
)
: null,
title: new Text(
'I agree.',
style: TextStyle(fontSize: 14.0),
),
controlAffinity: ListTileControlAffinity.leading,
activeColor: Colors.green,
);
The above answer is correct, however, if you want to display an error message that is more consistent with the default layout of a TextFormField widget error message, then wrap the Text widget in a Padding widget, and give it the hex colour #e53935.
Note: You may need to adjust the left padding to fit the CheckboxListTile widget is also wrapped in a Padding widget.
Check the code below:
bool _termsChecked = false;
CheckboxListTile(
activeColor: Theme.of(context).accentColor,
title: Text('I agree to'),
value: _termsChecked,
onChanged: (bool value) => setState(() => _termsChecked = value),
subtitle: !_termsChecked
? Padding(
padding: EdgeInsets.fromLTRB(12.0, 0, 0, 0),
child: Text('Required field', style: TextStyle(color: Color(0xFFe53935), fontSize: 12),),)
: null,
),