23

Below is a dialog to capture users input by using a textField and a button. The button is disabled when textField is empty, however it continues to become disabled when textField is filled with values. This is because the _textController.text state is not being updated (rendered again in this widget).

void _pushAdd() async {
await showDialog(
  context: this.context,
  builder: (BuildContext context) {
    return AlertDialog(
      title: Text('Add a custom word'),
      content: _renderForm(),
      actions: <Widget>[
        FlatButton(
          child: Text('ADD'),
          onPressed: (_textController.text.isNotEmpty) ? () =>  _addNewPair() : null,
        ),
      ],
    );
  },
);
// Changed _pushAdd as async to handle onClose and clear _textController upon exit
_textController.clear();

Currently _textController is initiated within the class at the top (not init).

var _textController = new TextEditingController();

The textField with the _textController is located here:

Widget _renderForm() {
return Container(
  height: 50.0,
  child: Column(
    crossAxisAlignment: CrossAxisAlignment.start,
    children: [
      TextField(
        autofocus: true,
        textCapitalization: TextCapitalization.words,
        controller: _textController,
        decoration: InputDecoration(
          hintText: 'RedPotato',
        ),
      ),
    ]
  )
);

}

My initial plan was to use an onChanged: + another state which stores the text. However I was doubtful if it was efficient to do that. So I ask, what is the standard way to handle TextField values real time so that other Widgets can listen to the changes?

Jesse
  • 2,690
  • 9
  • 15
  • 28

2 Answers2

48

You just have to listen the TextEditingController for text changes.

      var _textController = TextEditingController();

      @override
      void dispose() {
        // Clean up the controller when the Widget is disposed
        _textController.dispose();
        super.dispose();
      }

      @override
      void initState() {
        _textController.addListener((){
            //here you have the changes of your textfield
            print("value: ${_textController.text}");
            //use setState to rebuild the widget
            setState(() {

                    });
        });
        super.initState();
      }

For more info check this link : https://flutter.io/docs/cookbook/forms/retrieve-input

diegoveloper
  • 93,875
  • 20
  • 236
  • 194
  • You're an angel sir :) Thanks so much for all the help! That documentation looks perfect. – Jesse Dec 11 '18 at 05:43
  • you are welcome, don't forget to check all the docs from here: https://flutter.io/docs , there is a lot of info – diegoveloper Dec 11 '18 at 05:44
  • Sorry just to clarify, I would have to create a state variable to store the text? So _textController and .text initself cannot be updated like a state? – Jesse Dec 11 '18 at 08:06
  • You will have to update the variable inside the listener – diegoveloper Dec 11 '18 at 13:49
  • This will rebuild the whole widget tree right? There's a way to only update a stateless widget like a Text, down the tree? If this were a form, then the whole form will be rebuild on each key stroke as far as I understand. Also, it seems now TextFormField propagate onChanged callback, so it can be used on both TextField and TextFormField. – Sdlion Jul 18 '19 at 21:03
  • 1
    yes you could use AnimatedBuilder and ValueNotifier – diegoveloper Jul 18 '19 at 21:05
  • 1
    Thanks! In the end I used the more readable ValueListenableBuilder/ValueNotifier combo and it works like a charm. – Sdlion Jul 18 '19 at 22:25
  • @diegoveloper I applied the same approach, not working in my case. – s.j Jan 06 '21 at 12:19
  • it works fine but set state closes the active keyboard as well, is there anyway to update other widget on text change without doing set state as it is closing the keyboard as well on each text change event – Rajesh Koshti Jan 10 '22 at 10:49
0

If you are working with Flutter's Dialog and not a particular widget (like this example), below link is helpful.

https://www.didierboelens.com/2018/05/hint-5-how-to-refresh-the-content-of-a-dialog-via-setstate/

Jesse
  • 2,690
  • 9
  • 15
  • 28