Home » Android » android – Using TextFormField in Stateless widget is very difficult in flutter

android – Using TextFormField in Stateless widget is very difficult in flutter

Posted by: admin June 15, 2020 Leave a comment

Questions:

I am trying to use TextFormField in a stateless widget along with ScopedModel to deal with text in it and facing various issues as follow.

  1. I tried using controller for field, but everytime I enter some text and press done on keyboard, text gets cleared. No idea as to why.

  2. If I remove controller, text stays in field but new problem gets created as to how to get text from field. I solved it by using callback onFieldSubmitted.

  3. But turns out, onFieldSubmitted is only getting called when we click on done button on keyboard. If I enter text in field and instead of clicking ok, click on another field, callback won’t get called and I will have no way of tracking what user has entered in field.

Any solution for this?

Attaching sample code for issue.

  class LoginPageStateless extends StatelessWidget {

  final loginUsernameController = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      resizeToAvoidBottomPadding: true,
      body: ScopedModelDescendant<AccountModel>(
        builder: (context, child, model) {
          return Form(
            //key: _formKey,
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: <Widget>[
                TextFormField(
                  style: TextStyle(fontSize: 15.0),
                  decoration: InputDecoration(
                    labelText: 'Email id',
                    hintText: '[email protected]',
                  ),
                  controller: loginUsernameController,
                  onFieldSubmitted: model.updateLoginUsernameText,
                ),
                TextFormField(
                  style: TextStyle(fontSize: 15.0),
                  decoration: InputDecoration(
                    labelText: 'Password',
                  ),
                  controller: loginUsernameController,
                  onFieldSubmitted: model.updateLoginUsernameText,
                  obscureText: true,
                ),
              ],
            ),
          );
        },
      ),
    );
  }
}
How to&Answers:

You cannot and should not use Stateless widget for storing long-term variable.

The problem is, it’s exactly what you are trying to. TextEditingController is a class instance that should be kept between renders. But by storing it into a StatelessWidget you basically recreate it after every update.

You should instead convert your widget to Stateful. And move that controller into the State part

Answer:

I haven’t used a TextFormField till now, I always use TextField() for it’s simplicity and flexibility. I encountered similar problem when using Redux and stateless widgets as I have a single source of truth at the top level store. So, I had to create some callbacks inside a ViewModel then assign that callback to the text field callback ‘onChanged’ which takes in a string param.

CustomTextWidgetWrapper(
    onChangedCallback: viewModel.onChanged
),

In the TextField wrapped in the widget I do (not giving more details)

new TextField(
    controller: myController, // no use practically now
    onChanged: onChangedCallback,

And in the view model I get the string and dispatch to the central storage for reuse in other widget, like a button which takes the data and sends to server

static ViewModel fromStore(Store<AppState> store) {
    return new ViewModel(
        onChanged: (String textFieldText) {
            // I call dispatch or an API here if I want
            store.dispatch(new CallAPI(params: textFieldText);