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.
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,
);
},
),
),
),
);
}
}
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 or completely new answer are welcome.
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 {
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("#,##,##,###");
// The result of eight #s after the decimal point is that users will be able
// to input only eight digits after decimal.
NumberFormat numberFormat03 = NumberFormat("#,##,##,###.########");
// We want to stop taking digits after 8 digits succeding the decimal dot
// in the user input in consistent with the numberFormat03 formatting. We
// declare the following constant for that.
const int maxDigitsAfterDecimalPeroid = 8;
const int countOfAPeriod = 1;
print("########## str=$str");
String lastChar = "";
String extractedString = "";
int digitsBeforePeriod = str.indexOf(".");
if (str.length >
digitsBeforePeriod + countOfAPeriod + maxDigitsAfterDecimalPeroid) {
extractedString = str.substring(
0, str.indexOf(".") + (maxDigitsAfterDecimalPeroid + 1));
str = extractedString;
}
print("########## extracted_string=$extractedString");
if (str.isEmpty) {
return "";
}
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)) {
lastChar = str[str.length - 1];
print("########## lastChar=$lastChar");
if (lastChar == "0") {
String subStringBeforePeriod = "";
String subStringAfterPeriod = "";
String tmpStr = "";
int indexOfPeriod = str.indexOf(".");
subStringBeforePeriod = str.substring(0, indexOfPeriod);
print("########## subStringBeforePeriod=$subStringBeforePeriod");
subStringAfterPeriod = str.substring(indexOfPeriod + 1, str.length);
print("########## subStringAfterPeriod=$subStringAfterPeriod");
print("########## str with last char possibly = $str");
// return numberFormat03.format(double.parse(str)) + lastChar;
tmpStr =
numberFormat01_and_02.format(int.parse(subStringBeforePeriod));
print("tmpStr=$tmpStr");
// return numberFormat03.format(double.parse(str)) + lastChar;
return "${tmpStr}.${subStringAfterPeriod}";
}
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) {
print("########## value=$value");
value = value.replaceAll(",", "");
String myFormattedNumber = "";
myFormattedNumber = parseMyNumber(value);
if (myFormattedNumber != "NaN") {
RememberMyValue.value_previous_or_this_instance =
myFormattedNumber;
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}");
},
),
),
),
);
}
}