Flutter BlocBuilder displays previous state in TextFormField value

Issue

I am trying to create a TextFormField with increment and decrement buttons and TextFormField is editable "by hand" as well. But there is a small problem if I use BLoC with this – state "falls" one behind, meaning that when I tap "+" first time nothing changes, but when I tap it the second time it changes its value to 21 (and so on..).
I tried the same implementation with just a regular Text and it works as expected and updating properly.

I’m just wondering if my logic of how I am setting TextFormField is flawed:

  • Instantiating TextEditingController with default value amount (20);
  • On "+" tap:
    • Adding PlusEvent to increment current value
    • Getting amount value from state

Widget class:

class MyCalculation extends StatefulWidget {
  const MyCalculation({Key? key}) : super(key: key);

  @override
  State<MyCalculation> createState() => _MyCalculationState();
}

class _MyCalculationState extends State<MyCalculation> {
  late TextEditingController _controller;
  late MyCalcBloc _bloc;

  @override
  void initState() {
    super.initState();
    _bloc = context.read();
    _controller.text = _bloc.state.amount.toString();
  }

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

  @override
  Widget build(BuildContext context) {
    return BlocBuilder<MyCalcBloc, MyCalcState>(builder: (context, state) {
      return MyCustomTextFormField(
          controller: _controller,
          onChanged: (value) {},
          onPlusTap: () {
            _bloc.add(PlusEvent());
            _bloc.text = '${state.amount}';
          },
          onMinusTap: () {});
    });
  }
}

BLoC class:

class MyCalcBloc extends Bloc<MyCalcEvent, MyCalcState> {
  MyCalcBloc() : super(const MyCalcState(amount: 20)) {
    on<IncrementFromEvent>(_onPlusEvent);
  }

  void _onPlusEvent(PlusEvent event, Emitter<MyCalcState> emit) {
    final newValue = state.amount + 1;
    emit(MyCalcState(amount: newValue));
  }
}

Solution

You should instantiate TextEditingController within BlocProvider, that way you’ll get "current" state value displayed in TextFormField.

@override
  Widget build(BuildContext context) {
    return BlocBuilder<MyCalcBloc, MyCalcState>(builder: (context, state) {
      _controller = TextEditingController(text: state.amount.toString());
      return MyCustomTextFormField(
          controller: _controller,
          onChanged: (value) {},
          onPlusTap: () {
            _bloc.add(PlusEvent());
            _bloc.text = '${state.amount}';
          },
          onMinusTap: () {});
    });
  }

Answered By – rdev

Answer Checked By – Mary Flores (FlutterFixes Volunteer)

Leave a Reply

Your email address will not be published.