Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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,
                ),
              ],
            ),
          );
        },
      ),
    );
  }
}
like image 404
Amit Bhandari Avatar asked Aug 23 '18 07:08

Amit Bhandari


2 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

like image 155
Rémi Rousselet Avatar answered Oct 14 '22 22:10

Rémi Rousselet


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);
like image 22
Vijay Kumar Kanta Avatar answered Oct 14 '22 20:10

Vijay Kumar Kanta