should Bloc pattern be used for flutter textfield and if yes how?

2,524

The issue here happens because the value on TextField is always overridden on _controller.text = state.text; and continuously updated on onChanged(). One way to approach this is to only update the TextField values when the entry is submitted i.e. on onFieldSubmitted()

You can check for a similar approach here. While it doesn't use a Stream to listen for changes, the TextField value needs to be updated with a desired format.

Share:
2,524
Nayef Radwi
Author by

Nayef Radwi

Updated on December 21, 2022

Comments

  • Nayef Radwi
    Nayef Radwi over 1 year

    So I'm new to Bloc but I understand how it works from previously working on native android development, but what I'm trying to understand is should it be implemented to create something like a TextField. Now, keep in mind that I am trying to reuse this TextField multiple times and I want the bloc pattern to dynamically validate the input but should I implement it completely like handle the text inputted by the user?

    what I've done is I've created a simple bloc pattern for the text field to handle the user input but it does not save the values from time to time it overwrites the previous value and the cursor keeps moving to the beginning of the text

    import 'dart:math';
    
    import 'package:competitionapp/data_model/events/formTextFieldEvent.dart';
    import 'package:competitionapp/data_model/states/formTextFieldState.dart';
    import 'package:flutter_bloc/flutter_bloc.dart';
    
    FormTextFieldBloc bloc = FormTextFieldBloc();
    
    class FormTextFieldBloc extends Bloc<FormTextFieldEvent, FormTextFieldState> {
      void onChanged(String value) {
        if (value == null || value.isEmpty)
    //      todo change to handle errors
          this.add(TextChangedEvent("error"));
        else
          this.add(TextChangedEvent(value));
      }
    
      @override
      FormTextFieldState get initialState => FormTextFieldState.initState();
    
      @override
      Stream<FormTextFieldState> mapEventToState(FormTextFieldEvent event) async* {
        if (event is TextChangedEvent) {
          print("value received: ${event.eventText}");
          yield FormTextFieldState(event.eventText);
        }
      }
    }
    
    
    import 'package:competitionapp/data_model/blocModels/formTextFieldBloc.dart';
    import 'package:competitionapp/data_model/states/formTextFieldState.dart';
    import 'package:flutter/material.dart';
    import 'package:flutter_bloc/flutter_bloc.dart';
    
    // ignore: must_be_immutable
    class FormTextField extends StatelessWidget {
      final TextEditingController _controller;
      final String hint;
      final IconData iconData;
      final TextInputType inputType;
    
      final int maxLines;
      final int maxLength;
      final EdgeInsetsGeometry padding;
      final FormTextFieldBloc formTextFieldBloc;
    
      FormTextField(this._controller, this.formTextFieldBloc,
          {this.hint,
          this.iconData,
          this.inputType: TextInputType.text,
          this.maxLines: 1,
          this.maxLength,
          this.padding: const EdgeInsets.fromLTRB(15, 5, 15, 5)});
    
      @override
      Widget build(BuildContext context) {
        return Padding(
          padding: padding,
          child: BlocBuilder(
            bloc: formTextFieldBloc,
            builder: (context, FormTextFieldState state) {
              if (state.text.isNotEmpty && state.text != null) {
                _controller.text = state.text;
                print("state text: ${state.text}");
              }
              return TextField(
                onChanged: (value) {
                  print(value);
                  formTextFieldBloc.onChanged(_controller.text);
                },
                onEditingComplete: (){
                  print(_controller.text);
                },
                maxLength: maxLength ?? maxLength,
                maxLines: maxLines,
                keyboardType: inputType,
                controller: _controller,
                decoration: InputDecoration(
                  contentPadding: EdgeInsets.symmetric(vertical: 10),
                  border: OutlineInputBorder(
                      borderRadius: BorderRadius.circular(10),
                      borderSide: BorderSide(color: Colors.transparent, width: 0)),
                  focusedBorder: OutlineInputBorder(
                      borderRadius: BorderRadius.circular(10),
                      borderSide: BorderSide(color: Colors.transparent, width: 0)),
                  enabledBorder: OutlineInputBorder(
                      borderRadius: BorderRadius.circular(10),
                      borderSide: BorderSide(color: Colors.transparent, width: 0)),
                  hintText: hint,
                  hintStyle:
                      Theme.of(context).textTheme.caption.copyWith(fontSize: 18),
                  filled: true,
                  fillColor: Theme.of(context).cardColor,
                  prefixIcon: Icon(
                    iconData,
                    size: 16,
                    color: Theme.of(context).hintColor,
                  ),
                ),
              );
            },
          ),
        );
      }
    }