14

I am using provider for state management. I am in a situation where there are multiple types of fields in my form. The problem is with text-field Whenever I change Text it is behaving weirdly like the text entered is displayed in reverse order.

class MyProvider with ChangeNotifier{
  String _name;
  String get name => _name;
  setname(String name) {
    _name = name;
    notifyListeners();
  }
}

class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final MyProvider myProvider = Provider.of<MyProvider>(context);

    final TextEditingController _nameController = TextEditingController(
        text: myProvider.name,
    );

    return TextField(
        controller: _nameController,
        onChanged: myProvider.setname,
    );

}
vinayak bhanushali
  • 213
  • 1
  • 3
  • 9
  • Sir. your code is work perfectly on me. And is best solution for TextEditingController using provider in my opinion. the problem is your provider keep listening everytime you type. All you need is listen: false. `final MyProvider myProvider = Provider.of(context, listen: false);` – sunu dioh Jan 15 '21 at 10:23

2 Answers2

20

It happens because new instance of TextEditingController is created on every widget build, and information about current cursor position (TextEditingValue) is getting lost.

Create a controller once in initState method and dispose of it in dispose method.


class MyWidget extends StatefulWidget {
  @override
  _MyWidgetState createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget> {
  TextEditingController _nameController;

  @override
  void initState() {
    final MyProvider myProvider = Provider.of<MyProvider>(context, listen: false);

    super.initState();
    _nameController = TextEditingController(text: myProvider.name);
  }

  @override
  void dispose() {
    _nameController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    final MyProvider myProvider = Provider.of<MyProvider>(context);

    return TextField(
        controller: _nameController,
        onChanged: myProvider.setname,
    );
  }
}
Igor Kharakhordin
  • 9,185
  • 3
  • 40
  • 39
  • 3
    This method worked, thank you. I have heard that when using provider we can avoid using statefull widget and replace it with stateless widget but here we are using statefull widget. Is that not correct? – vinayak bhanushali May 18 '20 at 08:36
  • 2
    @vinayakbhanushali `TextEditingController` is a part of view (widget) and only exists when the view exists. While widget exists, a controller maintains it and has to be stored somewhere. When a widget is disposed, a controller should be disposed too. So it's better to store a controller close to its widget - in its state It's possible to save it in Provider, but it's not the best practice, because a controller is not related to business logic. But, with a help of Provider, everything related to business logic get moved from State of widgets into Provider. – Igor Kharakhordin May 18 '20 at 09:32
1

To store the text from the TextField into Provider you need to send the text property from the controller to the provider:

_nameController.addListener(() {
    myProvider.setName(_nameController.text);
});

This would also remove the problem you are getting the reverse text in the TextField

  • In order to use it, you'll also need to change the widget from Stateless to Statefull widget – Sudhanshu Bhagwat May 18 '20 at 08:44
  • Okay this method also worked. Can you tell me which is the most correct approach yours or the one by @igor-kharakhordin – vinayak bhanushali May 18 '20 at 09:13
  • 2
    @vinayakbhanushali If you add a listener to controller, it will be called on every event, including change of cursor's position, text selection etc. It's better to use `onChanged` parameter of `TextField`, just as you did. I'm not sure how that solves your problem. – Igor Kharakhordin May 18 '20 at 09:40
  • 1
    This doesn't seem to work if you want to change the provider's value from outside the widget - the text field won't update. – rjh Jan 31 '22 at 19:30