Flutter Enable/Disable Button based on TextFormField content

20,241

Solution 1

A simple way would be to set the autovalidate property of our TextFormField to true. This will automatically detect for changes on our TextFormField widget. We can then try to check if our TextFormField's value has a String length of 10 characters on the validator property . After that we can call setState to enable or disable our button (I use FlatButton in this example).

bool _btnEnabled = false;

...

@override
Widget build(BuildContext context){

  ...

  TextFormField(

    ...
    autovalidate: true,
    validator: (String txt){
      if (txt.length == 10){
        setState((){
          _btnEnabled = true;
        });
      } else {
        setState((){
          _btnEnabled = false;
        });
      }
    }

    ...

  FlatButton(
    onPressed: _btnEnabled == true ? yourCallback : null,
    child: ...

Solution 2

The state of the widget can be updated in the Form's onChanged callback which is called whenever any of the form fields' value changes. There you can use a form key to validate the form and set a flag to enable/disable the button. This solution allows you to scale to disable buttons in forms with multiple fields. For example,

/// Key used to reference the form.
final _formKey = GlobalKey<FormState>();

...

Form(
  key: _formKey,
  onChanged: () => setState(() => _enableBtn = _formKey.currentState.validate()),
  child: ListView(
    children: <Widget>[
      TextFormField(
        validator: (value) => value.length < 10 ?
          'Number must be at least 10 digits' : // return an error message
          null,
        ...
      ),
    ],
  ),
)

...

FlatButton(
  onPressed: _enableBtn ?
    () => _doSomething() :
    null, // setting onPressed to null disables the button.
  ...

Solution 3

you can use Flutter Reactive Forms. It's a model-driven approach to handling Forms inputs and validations, heavily inspired in Angular's Reactive Forms.

It's a very simple to use libray and in the documentation there is a section that explains how to Enable/Disable Submit button based on the validity of the entire form, not just a field.

Solution 4

The accepted answer seems to not work using the latest Flutter v1.7.8 (stable), it gives me the following error:

This TestForm widget cannot be marked as needing to build because the framework is already in the process of building widgets

The working version looks like the following:

...
autovalidate: true,
validator: (String txt){
      bool isValid = txt.length == 10;
      if (isValid != _btnEnabled) {
        WidgetsBinding.instance.addPostFrameCallback((_) {
          setState(() {
            _btnEnabled = txt.length == 10;
          });
        });
      } 
}

...
Share:
20,241
DrainBramage
Author by

DrainBramage

Updated on December 27, 2021

Comments

  • DrainBramage
    DrainBramage over 2 years

    How can I activate/deactivate a button based on the content of a TextFormField?

    I want to make sure a user can only press Button X if the TextFormField has 10 entered numbers (if it's a mobile number).

    Thanks!

  • pinkasey
    pinkasey over 2 years
    Thanks - your answer helped me a lot. Reactive Forms seems fantastic, I'm giving it a try. It looks very similar to Angular's reactive forms. The best part (for me) is that they support async validators, which is a feature I need.
  • Haris Ijaz Warraich
    Haris Ijaz Warraich over 2 years
    how do we validate multiple text fields using this approach that after every field is validated, the button gets enabled?