0

I would like to implement a simple validation on a TextField. My approach was to listen to the TextField's onChange event, apply my validation, set the value to controller.text and set controller.selection to the length of the previously set value.

Dartpad

For some reason for 123456789 input the TextField produces 864213579. Alternating between the beginning and the end when writing the upcoming character. With the debugPrints I can assert that the selection should always be at the end of the input.

What could be the issue here?

chrystolin
  • 1,067
  • 1
  • 9
  • 17

1 Answers1

0

Why don't you use TextInputFormatter?

This is the code.

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key}) : super(key: key);

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  var controller = TextEditingController();
  final _amountValidator = RegExInputFormatter.withRegex('^\$|^(0|([1-9][0-9]{0,}))(\\.[0-9]{0,})?\$');

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(''),
      ),
      body: Builder(
        builder: (context) {
          return 
            Column(
          children: <Widget>[
            TextField(
            inputFormatters: [_amountValidator],
            controller: controller,
            keyboardType: TextInputType.numberWithOptions(
              decimal: true,
              signed: false,
            ),           
          ),
            FlatButton(
              onPressed:(){
                print(controller.text);
              },
              child:Text("Test"),
            )
            ],
          );
        },
      ),
    );
  }
}






class RegExInputFormatter implements TextInputFormatter {
  final RegExp _regExp;

  RegExInputFormatter._(this._regExp);

  factory RegExInputFormatter.withRegex(String regexString) {
    try {
      final regex = RegExp(regexString);
      return RegExInputFormatter._(regex);
    } catch (e) {
      // Something not right with regex string.
      assert(false, e.toString());
      return null;
    }
  }

  @override
  TextEditingValue formatEditUpdate(
      TextEditingValue oldValue, TextEditingValue newValue) {
    final oldValueValid = _isValid(oldValue.text);
    final newValueValid = _isValid(newValue.text);
    if (oldValueValid && !newValueValid) {
      return oldValue;
    }
    return newValue;
  }

  bool _isValid(String value) {
    try {
      final matches = _regExp.allMatches(value);
      for (Match match in matches) {
        if (match.start == 0 && match.end == value.length) {
          return true;
        }
      }
      return false;
    } catch (e) {
      // Invalid regex
      assert(false, e.toString());
      return true;
    }
  }
}

REF: Flutter TextField input only decimal numbers

Shildra
  • 147
  • 1
  • 12