What I want to do is clear the entries after canceling the form submission. I'm trying to use _formKey.currentState.reset() but the fields are not being cleaned up. Should I have a method for cleaning field by field? Below I will show my code with the user name and weight fields but I have other fields (DropdownButton and Radio) that I decided not to put in the code so as not to get too long:
class UserDetailForm extends StatefulWidget {
final User user;
const UserDetailForm(this.user);
@override
_UserDetailFormState createState() => _UserDetailFormState();
}
class _UserDetailFormState extends State<UserDetailForm> {
final UserController controller = UserController();
final _formKey = GlobalKey<FormState>();
@override
Widget build(BuildContext context) {
return Scaffold(
body: SingleChildScrollView(
padding: EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0),
child: Form(
key: _formKey,
autovalidate: true,
child: Column(
children: <Widget>[
TextFormField(
initialValue: widget.user.name,
decoration: const InputDecoration(labelText: 'Name *'),
validator: (value) {
if (value.isEmpty) {
return 'Insert your name';
}
return null;
},
onChanged: (value) {
setState(() => widget.user.name = value);
}),
TextFormField(
initialValue: widget.user.weight,
decoration: const InputDecoration(
labelText: 'Weight',
),
onChanged: (value) {
setState(() => widget.user.weight = value);
}),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
MaterialButton(
child: Text("Cancel"),
onPressed: () {
_formKey.currentState.reset(); //NOT WORKING, SHOULD CLEAN THE FORM
Navigator.of(context).pop();
},
),
MaterialButton(
child: Text("Save"),
onPressed: () async {
if (_formKey.currentState.validate()) {
controller.updateUser(widget.user);
Navigator.of(context).pop();
}
},
),
],
),
],
),
),
),
);
}
}
#Edit 1 - Using TextEditingController (only for weight) and the problem still, the entries after canceling the form submission are not being cleaned up
class UserDetailForm extends StatefulWidget {
final User user;
const UserDetailForm(this.user);
@override
_UserDetailFormState createState() => _UserDetailFormState();
}
class _UserDetailFormState extends State<UserDetailForm> {
final UserController controller = UserController();
final _formKey = GlobalKey<FormState>();
TextEditingController weightController;
initState() {
weightController = TextEditingController(text: widget.user.weight);
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: SingleChildScrollView(
padding: EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0),
child: Form(
key: _formKey,
autovalidate: true,
child: Column(
children: <Widget>[
TextFormField(
initialValue: widget.user.name,
decoration: const InputDecoration(labelText: 'Name *'),
validator: (value) {
if (value.isEmpty) {
return 'Insert your name';
}
return null;
},
onChanged: (value) {
setState(() => widget.user.name = value);
}),
TextFormField(
controller: weightController,
decoration: const InputDecoration(
labelText: 'Weight',
),
onChanged: (value) {
setState(() => widget.user.weight = value);
}),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
MaterialButton(
child: Text("Cancel"),
onPressed: () {
_formKey.currentState.reset();
weightController.text = "";
Navigator.of(context).pop();
},
),
MaterialButton(
child: Text("Save"),
onPressed: () async {
if (_formKey.currentState.validate()) {
controller.updateUser(widget.user);
Navigator.of(context).pop();
}
},
),
],
),
],
),
),
),
);
}
}
_formKey.currentState.reset() resets every FormField that is a descendant of this Form back to its FormField.initialValue, and that's what is happening in your code. When clicking cancel, the initialValue is still in the screen. To fix that, you need to use a TextEditingController. So first initialize the controller:
TextEditingController weightController = TextEditingController(text: "test");
TextEditingController nameController = TextEditingController(text: "test1");
And give each controller an initial value (ex: test). Then bind each controller the field:
TextFormField(
controller : emailController,
decoration: const InputDecoration(labelText: 'Name *'),
validator: (value) {
if (value.isEmpty) {
return 'Insert your name';
}
return null;
}),
TextFormField(
controller: nameController,
decoration: const InputDecoration(
labelText: 'Weight',
)),
remove the initialValue property since you are already initializing the field when creating a controller. Finally under onPressed():
onPressed: () {
_formKey.currentState.reset();
nameController.text = "";
emailController.text = "";
},
change the value of the initial test to empty string.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With