How to clear error message in TextFormField in Flutter

here is a suitable solution to this problem.

You don't actually need to use onChanged or any tips causing side-effects, I solved it by creating a class property which is initialized to false:

bool _autovalidate = false;

The Form Widget has a named property autovalidate. You should pass it the previous boolean:

Form(
  key: _textKey,
  autovalidate: _autovalidate,
  ... 
)

And in your Submit button onPressed() method, you should update the _autovalidate boolean to be true if the form is invalid, this will make the form to auto validate the TextFormField on every onChanged call:

RaisedButton(
  onPressed: () {
    if (_textKey.currentState.validate()) {
      print('valid');
    } else {
      print('invalid');
      setState(() => _autoValidate = true);
    }
  },
  child: Text(login),
)

I hope it helped Somebody.

EDIT (Nov 2020)

autovalidate was deprecated after v1.19.0.
Instead use autovalidateMode:

Form(
  autovalidateMode: AutovalidateMode.onUserInteraction`.
  ...
)

January 2021

...

AutovalidateMode _autoValidate = AutovalidateMode.disabled;
Form(
  key: _textKey,
  autovalidateMode: _autovalidate,
  ... 
)
RaisedButton(
  onPressed: () {
    if (_textKey.currentState.validate()) {
      print('valid');
    } else {
      print('invalid');
      setState(() => _autoValidate = AutovalidateMode.always);
    }
  },
  child: Text("login"),
)

The problem here is errorText is automatically managed by the validator field of the TextFormField. At the same time, the simple solution is to handle the errorText manually.

Step 1: Create

  • String field, _errorText initialised to null. The field will hold the error message that needs to be shown.
  • Boolean field, _error initialised to false. The filed is true if there is an error otherwise false.

Step 2:

  • Assign _errorText to TextFormField

Step 3 (Important):

  • Make sure that TextFormField validator returns a null value.

  • Handle the validation here and assign the proper error message to _errorText.

  • Update _error state correspondingly.

Step 4 (Important):

  • Reset _errorText and _error. This will remove the error from field soon as you start editing.

Step 5:

  • Trigger field validation in the onFieldSubmitted and manage your code flow...
import 'package:flutter/material.dart';

class WorkGround extends StatefulWidget {
  @override
  _WorkGroundState createState() => _WorkGroundState();
}

class _WorkGroundState extends State<WorkGround> {
  final _formKey = GlobalKey<FormState>();
  final _usernameFocusNode = FocusNode();
  final _phoneNumberFocusNode = FocusNode();

  /*
  * Step 1.
  * */
  String _userNameErrorText;
  bool _userNameError = false;
  String _phoneNumberErrorText;
  bool _phoneNumberError = false;

  @override
  Widget build(BuildContext context) {
    return Form(
      key: _formKey,
      child: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: <Widget>[
            TextFormField(
              focusNode: _usernameFocusNode,
              decoration: InputDecoration(
                labelText: 'Username',
                /*
                * Step 2
                * */
                errorText: _userNameErrorText, // Handling error manually
              ),
              textInputAction: TextInputAction.next,
              /*
              * Step 3
              * */
              validator: (value) {
                setState(() {
                  if(value.isEmpty) {
                    _userNameError = true;
                    _userNameErrorText = 'Enter Username';
                  }
                });
                return null; // Return null to handle error manually.
              },
              /*
              * Step 4
              * */
              onChanged: (value) {
                setState(() {
                  _userNameError = false;
                  _userNameErrorText = null; // Resets the error
                });
              },
              /*
              * Step 5
              * */
              onFieldSubmitted: (value) {
                _formKey.currentState.validate(); // Trigger validation
                if(!_userNameError) {
                  FocusScope.of(context).requestFocus(_phoneNumberFocusNode);
                }
              },
            ),
            TextFormField(
              focusNode: _phoneNumberFocusNode,
              decoration: InputDecoration(
                labelText: 'Phone Number',
                /*
                * Step 2
                * */
                errorText: _phoneNumberErrorText, // Handling error manually
              ),
              textInputAction: TextInputAction.done,
              /*
              * Step 3
              * */
              validator: (value) {
                setState(() {
                  if(value.isEmpty) {
                    _phoneNumberError = true;
                    _phoneNumberErrorText = 'Enter Phone number';
                  } else if( value.length < 10) {
                    _phoneNumberError = true;
                    _phoneNumberErrorText = 'Invalid Phone number';
                  }
                });
                return null; // Return null to handle error manually.
              },
              /*
              * Step 4
              * */
              onChanged: (value) {
                setState(() {
                  _phoneNumberError = false;
                  _phoneNumberErrorText = null; // Resets the error
                });
              },
              /*
              * Step 5
              * */
              onFieldSubmitted: (value) {
                _formKey.currentState.validate(); // Trigger validation
                if(!_phoneNumberError) {
                  // submit form or whatever your code flow is...
                }
              },
            ),
          ],
        ),
      ),
    );
  }
}

Tags:

Flutter