skip to Main Content

I’m trying to display the user input double (may be without decimal dot and that follows) number as a formatted value e.g. 123456789012.1234 as 12345,67,89,012.1234 using not the western numbering system, but using Indian Subcontinent numbering system as shown. Preferably, no commas after crore.

With the intl package, I could display formatted output, but I also need to format the input being entered by the user in the text input filed. And this I could not manage to get working.

The minimal code:

I’ve written the following minimal code to show my problem. Here, as I enter 123 an then 4 a comma appears at the correct place (i.e. 1,234) but then when I enter the fifth digit i.e. 5 in succession, only 0 is displayed which is erroneous.

How can I fix this?

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

final _controller = TextEditingController();

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('intl Formatter With Formatted Text Field'),
        ),
        body: Padding(
          padding: const EdgeInsets.all(20.0),
          child: TextField(
            controller: _controller,
            keyboardType: TextInputType.number,
            onChanged: (value) {
              NumberFormat numberFormat = NumberFormat("#,##,##,###.########");
              final formattedValue =
                  numberFormat.format(double.tryParse(value) ?? 0.0);
              _controller.value = TextEditingValue(
                text: formattedValue,
              );
            },
          ),
        ),
      ),
    );
  }
}

2

Answers


  1. Chosen as BEST ANSWER

    What I needed was to format the input double value in TextField to be shown in Indian Numbering Format. In the question I posted my minimal code which tried to do so incompletely. With the help form the answer from @frankenapps here, and my trial and errors, I have finally managed to get what I wanted.

    More suggestions to improve the code are welcome.

    The Final Code:

    import 'package:flutter/material.dart';
    import 'package:intl/intl.dart';
    
    final _controller = TextEditingController();
    
    void main() => runApp(MyApp());
    
    class RememberMyValue {
      static String value_previous_or_this_instance = "";
    }
    
    class MyApp extends StatelessWidget {
      bool doesContainDecimalPoint(String str) {
        if (str.contains('.')) {
          return true;
        } else {
          return false;
        }
      }
    
      String parseMyNumber(String str) {
        // Function to parse only positive numbers (without any prefix):
        RegExp myNumber01 = RegExp(r'^[0-9]+$');
        RegExp myNumber02 = RegExp(r'^[0-9]+.$');
        RegExp myNumber03 = RegExp(r'^[0-9]+.[0-9]+$');
    
        NumberFormat numberFormat01_and_02 = NumberFormat("#,##,##,###");
        NumberFormat numberFormat03 = NumberFormat("#,##,##,###.########");
    
        if (myNumber01.hasMatch(str)) {
          return numberFormat01_and_02.format(int.parse(str));
        } else {
          if (myNumber02.hasMatch(str)) {
            // Here str.replaceAll(".", "") chops the trailing dot from the input, and
            // finally the return statement is interpolated such that there is a dot
            // appended at the end of the number.
            return "${numberFormat01_and_02.format(int.parse(str.replaceAll(".", "")))}.";
          } else {
            if (myNumber03.hasMatch(str)) {
              return numberFormat03.format(double.parse(str));
            } else {
              return "NaN";
            }
          }
        }
      }
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          home: Scaffold(
            appBar: AppBar(
              title: const Text('intl Formatter With Formatted Text Field'),
            ),
            body: Padding(
              padding: const EdgeInsets.all(20.0),
              child: TextField(
                controller: _controller,
                keyboardType: TextInputType.number,
                onChanged: (value) {
                  value = value.replaceAll(",", "");
    
                  String myFormattedNumber = "";
                  // String value_previous_or_this_instance = "";
                  myFormattedNumber = parseMyNumber(value);
                  if (myFormattedNumber != "NaN") {
                    RememberMyValue.value_previous_or_this_instance = value;
                    print(
                        "########## value_previous_or_this_instance = ${RememberMyValue.value_previous_or_this_instance}");
                  } else {
                    print("########## NaN");
                  }
    
                  _controller.value = TextEditingValue(
                    text: RememberMyValue.value_previous_or_this_instance,
                  );
                  print("########## _controller.text = ${_controller.text}");
                },
              ),
            ),
          ),
        );
      }
    }
    

  2. The issue with your current code is that the value contains a comma (,) after entering 1234. When entering the next character (e.g. 5) 1,2345 is passed to double.tryParse which fails to parse the value, because it contains a comma and the parser only respects dots (.) for separating decimal places.

    One option to circumvent this is to remove all commas before passing the value to double.tryParse, like so:

    value = value.replaceAll(",", "");
    

    Here is dart.dev sample.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search