Skip to content

TextField doesn't respect maxLength limit #67898

Closed

Description

@gocal

Doctor summary

Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, 1.22.1, on Linux, locale en_US.UTF-8)
[✓] Android toolchain - develop for Android devices (Android SDK version 29.0.2)
[✓] Android Studio (version 4.0)
[✓] VS Code (version 1.50.0)
[✓] Connected device (1 available)

Steps to Reproduce

  1. Create TextField as follows:
      TextField(
              maxLength: 5,
            ),

or

      TextField(
              maxLength: 5,
              inputFormatters: [LengthLimitingTextInputFormatter(5)],
            ),
  1. Start typing some text

Expected results:

  • TextField allows to enter only maxLength characters

Actual results:

  • it's possible to enter more than maxLength characters

Looks like it's related to the following change introduced in flutter 1.22 - https://github.com/flutter/flutter/pull/63754/files

packages/flutter/lib/src/services/text_formatter.dart

  ///
  /// ### Composing text behaviors
  ///
  /// There is no guarantee for the final value before the composing ends.
  /// So while the value is composing, the constraint of [maxLength] will be
  /// temporary lifted until the composing ends.
  ///
  /// In addition, if the current value already reached the [maxLength],
  /// composing is not allowed.

Activity

  1. Gridzzle commented on Oct 12, 2020

    @Gridzzle

    try :
    maxLengthEnforced: true,
    instead of inputFormatters

  2. gocal commented on Oct 12, 2020

    @gocal
    Author

    @Gridzzle maxLengthEnforced is by default set to true so it doesn't change anything.

  3. Gridzzle commented on Oct 12, 2020

    @Gridzzle

    @Gridzzle maxLengthEnforced is by default set to true so it doesn't change anything.

    it works perfect with me

  4. xu-baolin commented on Oct 12, 2020

    @xu-baolin
    Member

    @gocal Hi
    This is designed.
    You are during Composing time, see also

    /// ### Composing text behaviors

  5. gocal commented on Oct 12, 2020

    @gocal
    Author

    @xu-baolin I've noticed this behavior has been introduced in 1.22 release (https://github.com/flutter/flutter/pull/63754/files) but I think this is not how I'd expect "maxLength" would work.

  6. darshankawar commented on Oct 12, 2020

    @darshankawar
    Member

    @gocal
    There are similar open issues describing your case, 67236 and 67828 which also talks about a related deleting characters in textfield.
    I'd suggest you to follow-up in above issues for updates and any questions.
    Closing this as duplicate. If you disagree, write in comments and I'll reopen.
    Thanks.

  7. xu-baolin commented on Oct 12, 2020

    @xu-baolin
    Member

    @gocal
    There are similar open issues describing your case, 67236 and 67828 which also talks about a related deleting characters in textfield.
    I'd suggest you to follow-up in above issues for updates and any questions.
    Closing this as duplicate. If you disagree, write in comments and I'll reopen.
    Thanks.

    Not the same issue herehere :)

  8. pedromassangocode commented on Oct 12, 2020

    @pedromassangocode

    I was able to reproduce this issue on latest master and stable channel. Testing the same code with Flutter 1.20.0 we have a different behavior (the correct one). I also believe maxLength should be respected all the time.

    This was introduced by #63754.

    Cc @justinmc

    Flutter 1.20 (good) Flutter 1.23 (bad)
    sample code
    import 'package:flutter/material.dart';
    
    void main() => runApp(MyApp());
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter Demo',
          home: Scaffold(
            body: Center(
              child: TextField(
                maxLength: 5,
              ),
            ),
          ),
        );
      }
    }
    flutter doctor
    /Users/pedromassango/dev/SDKs/flutter_master/bin/flutter doctor --verbose
    [✓] Flutter (Channel master, 1.23.0-8.0.pre.284, on Mac OS X 10.15.7 19H2 x86_64, locale en)
        • Flutter version 1.23.0-8.0.pre.284 at /Users/pedromassango/dev/SDKs/flutter_master
        • Framework revision eefcff900c (2 days ago), 2020-10-10 23:42:02 +0200
        • Engine revision 11d756a62e
        • Dart version 2.11.0 (build 2.11.0-207.0.dev)
    
    [✓] Android toolchain - develop for Android devices (Android SDK version 30.0.1)
        • Android SDK at /Users/pedromassango/Library/Android/sdk
        • Platform android-30, build-tools 30.0.1
        • Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java
        • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b3-6222593)
        • All Android licenses accepted.
    
    [✓] Xcode - develop for iOS and macOS (Xcode 12.0.1)
        • Xcode at /Applications/Xcode.app/Contents/Developer
        • Xcode 12.0.1, Build version 12A7300
        • CocoaPods version 1.9.3
    
    [✓] Chrome - develop for the web
        • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome
    
    [✓] Android Studio (version 4.0)
        • Android Studio at /Applications/Android Studio.app/Contents
        • Flutter plugin can be installed from:
          🔨 https://plugins.jetbrains.com/plugin/9212-flutter
        • Dart plugin can be installed from:
          🔨 https://plugins.jetbrains.com/plugin/6351-dart
        • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b3-6222593)
    
    [✓] VS Code (version 1.48.2)
        • VS Code at /Applications/Visual Studio Code.app/Contents
        • Flutter extension version 3.14.1
    
    [✓] Connected device (4 available)
        • Android SDK built for x86 (mobile) • emulator-5554 • android-x86    • Android 10 (API 29) (emulator)
        • macOS (desktop)                    • macos         • darwin-x64     • Mac OS X 10.15.7 19H2 x86_64
        • Web Server (web)                   • web-server    • web-javascript • Flutter Tools
        • Chrome (web)                       • chrome        • web-javascript • Google Chrome 85.0.4183.121
    
    ! Doctor found issues in 1 category.
    Process finished with exit code 0
    
  9. added
    a: text inputEntering text in a text field or keyboard related problems
    frameworkflutter/packages/flutter repository. See also f: labels.
    has reproducible stepsThe issue has been confirmed reproducible and is ready to work on
    on Oct 12, 2020
  10. 83 remaining items

  11. Faiyyazauxy commented on Dec 4, 2020

    @Faiyyazauxy

    Even i am seeing maxlength problem now previously it used to work fine. Even inputformatters are not working for length. Please help.

    And yes the number first maxlength behaviour works awesome like what others has mentioned

  12. Faiyyazauxy commented on Dec 4, 2020

    @Faiyyazauxy

    I've solved this problem by creating child class from LengthLimitingTextInputFormatter and overriding formatEditUpdate() method
    What is changed you can see between 'start of fix' and 'end of fix' comments

    class ModifiedLengthLimitingTextInputFormatter extends LengthLimitingTextInputFormatter {
      final int _maxLength;
    
      ModifiedLengthLimitingTextInputFormatter(this._maxLength) : super(_maxLength);
    
      @override
      TextEditingValue formatEditUpdate(
        TextEditingValue oldValue,
        TextEditingValue newValue,
      ) {
        // Return the new value when the old value has not reached the max
        // limit or the old value is composing too.
        if (newValue.composing.isValid) {
          if (maxLength != null &&
              maxLength > 0 &&
              oldValue.text.characters.length == maxLength &&
              !oldValue.composing.isValid) {
            return oldValue; 
          //START OF FIX
          } else if (newValue.text.characters.length > maxLength) {
            return oldValue;
          }
         //END OF FIX
          return newValue;
        }
        if (maxLength != null && maxLength > 0 && newValue.text.characters.length > maxLength) {
          // If already at the maximum and tried to enter even more, keep the old
          // value.
          if (oldValue.text.characters.length == maxLength) {
            return oldValue;
          }
          return truncate(newValue, maxLength);
        }
        return newValue;
      }
    
      static TextEditingValue truncate(TextEditingValue value, int maxLength) {
        final CharacterRange iterator = CharacterRange(value.text);
        if (value.text.characters.length > maxLength) {
          iterator.expandNext(maxLength);
        }
        final String truncated = iterator.current;
        return TextEditingValue(
          text: truncated,
          selection: value.selection.copyWith(
            baseOffset: min(value.selection.start, truncated.length),
            extentOffset: min(value.selection.end, truncated.length),
          ),
          composing: TextRange.empty,
        );
      }
    }
    

    Awesome this works fine as it's suppose to

  13. AlexV525 commented on Dec 4, 2020

    @AlexV525
    Member

    @Faiyyazauxy There is a valid workaround at here: #67898 (comment)

  14. Faiyyazauxy commented on Dec 4, 2020

    @Faiyyazauxy

    @Faiyyazauxy There is a valid workaround at here: #67898 (comment)

    Okay @AlexV525 Thanks will try and check

  15. Faiyyazauxy commented on Dec 4, 2020

    @Faiyyazauxy

    @Faiyyazauxy There is a valid workaround at here: #67898 (comment)

    This is the flutter's default behaviour i need to stop the users typing beyond the maxlength. This lets the user type even after the maxlength and then remove the text after the maxlength on submit. Anyway thanks for the help

  16. AlexV525 commented on Dec 6, 2020

    @AlexV525
    Member

    @derencewalk1 From your screenshots, number at first usually means that you're not typing a word, so the keyboard didn't bring you into composition, which will be enforced truncate because it has no composition. There are no special handle compare to typing a regular word.

  17. AlexV525 commented on Dec 9, 2020

    @AlexV525
    Member

    Hi all! The PR has landed on the master with some behaviors update. Basically we make the truncate behavior follow the platform that users on by default. If anyone still encountering some similar issues, feel free to provide more info or use cases, and it's better to file a new issue. Thanks for all your patience for participating our discussions and waiting this to land.

  18. RalphNoel commented on Dec 14, 2020

    @RalphNoel

    @AlexV525 Hi, it's working fine in when i set KeyboardType is number, but maxLength is not working in AlphaNumeric Characters.

    For Eg.

    I tried to set a bank IFS Code(INDIA) in TextFormField, the maxLength is not working in this Condition..

  19. cassioseffrin commented on Dec 16, 2020

    @cassioseffrin

    In my opinion this issue was closed without a good argument. The version above the 1.20 have this breaking change, the argument that Gboard is creating a composing region isn't enough.

    If anyone have found a solution to limit the text input by length it will be very appreciated by the flutter community.

  20. AlexV525 commented on Dec 16, 2020

    @AlexV525
    Member

    Comments that follow the code of conduct are always welcome, but IMO after 96+213 comments and 87 commits we do have the most effective solution. You can provide more info about your proposal in a new issue in anytime.

  21. cassioseffrin commented on Dec 17, 2020

    @cassioseffrin

    Today I have made a test on the dev channel and the maxLength is working in both keyboard types (numeric/alpha numeric). I will appreciate to know when those commits will be in the stable channel.

  22. Okladnoj commented on May 18, 2021

    @Okladnoj

    I've solved this problem by creating child class from LengthLimitingTextInputFormatter and overriding formatEditUpdate() method
    What is changed you can see between 'start of fix' and 'end of fix' comments

    class ModifiedLengthLimitingTextInputFormatter extends LengthLimitingTextInputFormatter {
      final int _maxLength;
    
      ModifiedLengthLimitingTextInputFormatter(this._maxLength) : super(_maxLength);
    
      @override
      TextEditingValue formatEditUpdate(
        TextEditingValue oldValue,
        TextEditingValue newValue,
      ) {
        // Return the new value when the old value has not reached the max
        // limit or the old value is composing too.
        if (newValue.composing.isValid) {
          if (maxLength != null &&
              maxLength > 0 &&
              oldValue.text.characters.length == maxLength &&
              !oldValue.composing.isValid) {
            return oldValue; 
          //START OF FIX
          } else if (newValue.text.characters.length > maxLength) {
            return oldValue;
          }
         //END OF FIX
          return newValue;
        }
        if (maxLength != null && maxLength > 0 && newValue.text.characters.length > maxLength) {
          // If already at the maximum and tried to enter even more, keep the old
          // value.
          if (oldValue.text.characters.length == maxLength) {
            return oldValue;
          }
          return truncate(newValue, maxLength);
        }
        return newValue;
      }
    
      static TextEditingValue truncate(TextEditingValue value, int maxLength) {
        final CharacterRange iterator = CharacterRange(value.text);
        if (value.text.characters.length > maxLength) {
          iterator.expandNext(maxLength);
        }
        final String truncated = iterator.current;
        return TextEditingValue(
          text: truncated,
          selection: value.selection.copyWith(
            baseOffset: min(value.selection.start, truncated.length),
            extentOffset: min(value.selection.end, truncated.length),
          ),
          composing: TextRange.empty,
        );
      }
    }
    
    • Add LITTLE FIX
    
    class ModifiedLengthLimitingTextInputFormatter extends LengthLimitingTextInputFormatter {
      final int _maxLength;
    
      ModifiedLengthLimitingTextInputFormatter(this._maxLength) : super(_maxLength);
    
      @override
      TextEditingValue formatEditUpdate(
        TextEditingValue oldValue,
        TextEditingValue newValue,
      ) {
        // Return the new value when the old value has not reached the max
        // limit or the old value is composing too.
        if (newValue.composing.isValid) {
          if (maxLength != null &&
              maxLength > 0 &&
              oldValue.text.characters.length == maxLength &&
              !oldValue.composing.isValid) {
            //START OF LITTLE FIX
            if (oldValue.text.length > newValue.text.length) {
              return newValue;
            }
            //END OF LITTLE FIX
            return oldValue;
            //START OF FIX
          } else if (newValue.text.characters.length > maxLength) {
            return oldValue;
          }
          //END OF FIX
          return newValue;
        }
        if (maxLength != null && maxLength > 0 && newValue.text.characters.length > maxLength) {
          // If already at the maximum and tried to enter even more, keep the old
          // value.
          if (oldValue.text.characters.length == maxLength) {
            return oldValue;
          }
          return truncate(newValue, maxLength);
        }
        return newValue;
      }
    
      static TextEditingValue truncate(TextEditingValue value, int maxLength) {
        final CharacterRange iterator = CharacterRange(value.text);
        if (value.text.characters.length > maxLength) {
          iterator.expandNext(maxLength);
        }
        final String truncated = iterator.current;
        return TextEditingValue(
          text: truncated,
          selection: value.selection.copyWith(
            baseOffset: min(value.selection.start, truncated.length),
            extentOffset: min(value.selection.end, truncated.length),
          ),
          composing: TextRange.empty,
        );
      }
    }
    
    
  23. github-actions commented on Aug 7, 2021

    @github-actions

    This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of flutter doctor -v and a minimal reproduction of the issue.

  24. locked as resolved and limited conversation to collaborators on Aug 7, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

P1High-priority issues at the top of the work lista: text inputEntering text in a text field or keyboard related problemsa: typographyText rendering, possibly libtxtc: proposalA detailed proposal for a change to Flutterc: regressionIt was better in the past than it is nowcustomer: crowdAffects or could affect many people, though not necessarily a specific customer.found in release: 1.22Found to occur in 1.22found in release: 1.23Found to occur in 1.23frameworkflutter/packages/flutter repository. See also f: labels.has reproducible stepsThe issue has been confirmed reproducible and is ready to work onp: material_uimaterial_ui package in flutter/packages

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions