Amit Bhandari
Amit Bhandari

Reputation: 3134

Using TextFormField in Stateless widget is very difficult in flutter

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,
                ),
              ],
            ),
          );
        },
      ),
    );
  }
}

Upvotes: 20

Views: 25619

Answers (4)

softweng
softweng

Reputation: 334

changes textEditingController declaration as static:

static final loginUsernameController = TextEditingController();

Upvotes: 0

Yehia El-azab
Yehia El-azab

Reputation: 19

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

Let's assume that you have a basic behavior like when the user tap anywhere the keyboard will close , in a stateless widget that would be impossible as every time the keyboard open or close it will rebuild and creates a new instance of your text controllers ,

so in this case using a stateful widget is a must and putting your controllers in the state class

Upvotes: 1

Vijay Kumar Kanta
Vijay Kumar Kanta

Reputation: 1131

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);

Upvotes: 3

R&#233;mi Rousselet
R&#233;mi Rousselet

Reputation: 277037

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

Upvotes: 40

Related Questions