user3249281
user3249281

Reputation: 535

flutter - update TextField/TextEditingController via state (provider/consumer)

i have a TextField on a "page". i have a TextEditingController hooked to it. I can successfully set the value of the TextField via something easy like:

usernameController.text = '1234';

however, i need to be able to change this field from a child page. the use case is a login form where the user logs out from inside the app. when i return to the login page, i want the username/password to be wiped out/deleted. right now, the values are still there (showing whatever is currently in usernameController.text)

overall, i'm managing state via Provider. i can set and retrieve/display state in other places in my app with no problem. the issue becomes that the controller is setup via dart code in initState(). it is not part of a widget that gets rebuilt.

i can setup the TextField widget within a consumer. the builder gets called when state is updated in the child page (confirmed with the debug print statement) but the widget itself does not reflect the new value of the state (it still has the old username and it is not blanked out).

                            Consumer<myAppState>(
                          builder: (context, appState, child) {
                            print("in builder for consumer: ");
                            print(appState.username);
                            return Container(
                                width: 200,
                                child: TextField(
                                  controller: usernameController,
                                  onChanged: (value) => _saveUsername(value),
                                  decoration: InputDecoration(
                                    hintText: 'Username',
                                    prefixIcon: Icon(Icons.account_circle),
                                  ),
                                ));
                          }),

I've tried replacing

usernameController.text = '1234';

with:

usernameController.text = Provider.of<myAppState>(context, listen: true).username;

but that does not seem to work.

it seems this "non-pure" widget (because of the controller being handled programatically) doesn't sit pretty within the Consumer model which wants to redraw widgets.

anyone have any thoughts?

thanks!

Upvotes: 7

Views: 15015

Answers (2)

Evan Simpson
Evan Simpson

Reputation: 161

As other comments have described:

Setting a ChangeNotifier attribute to null and calling NotifyListeners() such as that of a TextEditingController text value will not update statements checking for null

Upvotes: 1

Hemanth Raj
Hemanth Raj

Reputation: 34769

One possible way is to check make a check in the builder if the value in state and controller matches and sync them.

Example:

Consumer<myAppState>(
  builder: (context, appState, child) {
    print("in builder for consumer: ");
    print(appState.username);
    if (usernameController.text != appState.username) { // Or check if appState.username != null or what ever your use case is.
      usernameController.text = appState.username ?? '';
    }
    return Container(
      width: 200,
      child: TextField(
        controller: usernameController,
        onChanged: (value) => _saveUsername(value),
        decoration: InputDecoration(
          hintText: 'Username',
          prefixIcon: Icon(Icons.account_circle),
        ),
      ),
    );
  },
)

Hope that helps!

Upvotes: 11

Related Questions