Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flutter - Why formKey.currentState.reset doesn't actually clear fields?

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();
                      }
                    },
                  ),
                ],
              ),
            ],
          ),
        ),
      ),
    );
  }
}
like image 640
Liam Park Avatar asked Oct 31 '25 08:10

Liam Park


1 Answers

_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.

like image 144
Peter Haddad Avatar answered Nov 01 '25 21:11

Peter Haddad



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!