'Flutter: onSaved method of TextFormField not storing values to variables
I have a form which prompts the user to enter the address. The form is broken down into multiple TextFormField widgets which is defined in a file called address_widget.dart. These widgets are called from the file: AddressPage.dart. The form loads and gets validated properly but the values saved by the onSaved methods in address_widget.dart is not getting stored in the variables city and address in AddressPage.dart. When printing the variables city and address, null is printed. Is this the correct way to do it or am I missing something?
address_widget.dart
Widget buildCity(city) {
return TextFormField(
style: TextStyle(
fontFamily: 'Montserrat',
fontSize: 2 * SizeConfig.textMultiplier,
),
decoration: InputDecoration(
labelText: 'City',
),
validator: (String value) {
if (value.isEmpty) {
return 'This field is Required';
}
},
onSaved: (String value) {
city = value;
},
);
}
Widget buildAddress(address) {
return TextFormField(
style: TextStyle(
fontFamily: 'Montserrat',
fontSize: 2 * SizeConfig.textMultiplier,
),
decoration: InputDecoration(
labelText: 'Address',
),
validator: (String value) {
if (value.isEmpty) {
return 'This field is Required';
}
},
onSaved: (String value) {
address = value;
},
);
}
AddressPage.dart
import 'package:userproject/widgets/address_widget.dart';
class AddressPage extends StatefulWidget {
@override
_AddressPageState createState() => _AddressPageState();
}
class _AddressPageState extends State<AddressPage> {
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
String city;
String address;
@override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldKey,
body: Form(
key: _formKey,
child: Column(
children: <Widget>[
Text(
'Enter your Address',
style: TextStyle(
fontFamily: 'Montserrat',
fontWeight: FontWeight.bold,
),
buildCity(city),
buildAddress(address),
Row(
children: [
RaisedButton(
onPressed: () {
if (!_formKey.currentState.validate()) {
return;
}
_formKey.currentState.save();
print("city - $city"); // prints null
print("address- $address"); // prints null
},
),
],
)
],
),
),
),
}
}
The code has been simplified for easy reference.
Solution 1:[1]
You would have to use a TextEditingController to get the data from the text field.
class _AddressWidgetState extends State<AddressWidgetScreen> {
final myController = TextEditingController();
//a string to store the input from the text field
String city = '';
@override
void dispose() {
// Clean up the controller when the widget is disposed.
myController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Row(
children: [
//in your case TextFormField
TextField(
controller: myController,
),
RaisedButton(
onPressed: () {
//store the data from textfield to our new string
city = myController.text.toString();
//therest of your logic
},
textColor: Colors.white,),
BONUS TIP
Also, as good practice you should look to validate forms in a different class on runtime, using ValueObjects
Solution 2:[2]
Instead of using the onSaved you could try using the onChange callBack method it get assigned when ever the value gets changed. In order to use the on SavedMethod the a separate formKey must be added to the form section and then we should call the onSaved using the context of the key which we have assigned.
Solution 3:[3]
Have you considered Hot Restart? some code changes are not implemented until you do a 'Hot Restart'
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Ferdinand |
| Solution 2 | Abdul Kadhar |
| Solution 3 | Ahmed Nabil |
