0
votes

I'm porting my Swift app to Flutter and I have various textfields for time input so in order for user to only be able to input a valid time, I'm using Bloc to validate it. Basically at every input I send an ValidateText() event to OpeningTimesBloc with the string and textfield's TextEditingController in textfield's onChanged callback.

onChanged: (String value) {
                  print('textfield 1 onChanged: called');
                  BlocProvider.of(context)
                      .add(ValidatedText(text: value, controller: monMorOp));
                },

In OpeningTimesBloc I do the validation and yield a state with the validated string. In OpeningTimesScreen's BlocListener I get and use the new value. Now my complication is that I have 28 textfield as I have opening and closing time for morning and opening (e.g : TextEditingController monMorOp is Monday morning opening) and closing for afternoon for each weekday.

Do I need 28 TextEditingController and have a state check for each one in the BlocListener as:

if (state is ValidatedTextMonMorOp) {
            setState(() {
              monMorOp.controller.text = state.text;
            });

          }

or how can I just pass a reference just one and it will pilot the textfield the has the focus on? Something like this perhaps?

if (state is ValidatedText) {
            setState(() {
              state.controller.text = state.text;
            });

          }

As Always many thanks for your time and help.

2
Do you need that controller just to get the value and compare it? - Jitesh Mohite

2 Answers

4
votes

You have to create a separate Controller for each and every TextFormField because if you use same controller then there is no way to differentiate which TextFormField send which data.

Note: Don't forgot to dispose all controller otherwise you will get memory leak warning.

0
votes

After suggestions in accepted answer I turned away from using Bloc to validate TextField's text and made a local method that returns a String. in TextField's onChanged: callback I pass to the local method the actual text and assign its output to the TextField's controller text value.

the method:

String validateTimeFormat(String numb) {
    print('call back method called');
    print('input text is $numb');
    String cleanNumb = numb.replaceAll(RegExp(':'), '').substring(0);
    print('cleaned input text is $cleanNumb');
    RegExp isDigit = RegExp(r'^[\d]{1,4}$'); // is digit 1 to 4 characters
    RegExp input;
    String text;
    int lenght;
    String replaced;

    if (isDigit.hasMatch(cleanNumb)) {
      print('text is 1-4 digits');
      text = cleanNumb;
      lenght = text.length;

      if (lenght == 1) {
        // first digit
        //allow 0-2
        input = RegExp(r'^[0-2]$');
        input.hasMatch(text[0])
            ? print('text is : $text')
            : print('text is: not valid');
        return input.hasMatch(text[lenght - 1]) ? text : '';
      } else if (lenght == 2) {
        // second digit
        int first = int.parse(text[0]);
        print('firstDigit is $first');
        if (first == 1) {
          // allow 0-9
          input = RegExp(r'^[0-9]$');
          input.hasMatch(text[lenght - 1])
              ? print('text is : $text')
              : print('text is : ${text.substring(0, lenght - 1)}');
          return input.hasMatch(text[lenght - 1])
              ? text
              : text.substring(0, lenght - 1);
        } else {
          // allow 0-3
          input = RegExp(r'^[0-3]$');
          input.hasMatch(text[lenght - 1])
              ? print('text is : $text')
              : print('text is : ${text.substring(0, lenght - 1)}');
          return input.hasMatch(text[lenght - 1])
              ? text
              : text.substring(0, lenght - 1);
        }
      }
      if (lenght == 3) {
        //third digit
        // add : at lenght-1
        // allow 0-5
        input = RegExp(r'^[0-5]$');
        input.hasMatch(text[lenght - 1])
            ? replaced = text.replaceRange(2, lenght, ':${text.substring(2)}')
            : replaced = text.substring(0, lenght - 1);
        print('text is : $replaced');
        return replaced;
      }
      if (lenght == 4) {
        // fourth digit
        // allow 0-9
        input = RegExp(r'^[0-9]$');
        input.hasMatch(text[lenght - 1])
            ? replaced = text.replaceRange(2, lenght, ':${text.substring(2)}')
            : replaced = text.substring(0, lenght - 1);
        print('text is : $replaced');
        return replaced;
      }
    } else {
      // discard extra digit
      print('more than 4 digits');
      lenght = cleanNumb.length;
      replaced =
          cleanNumb.replaceRange(2, lenght, ':${cleanNumb.substring(2, 4)}');
      print('text is : $replaced');
      return replaced;
    }
  }

usage:

TextField(
                  controller: monMorCl,
                  autocorrect: true,
                  autofocus: true,
                  onChanged: (String value) {
                    monMorCl.text = validateTimeFormat(value);
                  },
                ),