how to format or separate textformfield parts in flutter - flutter

i have a text form field i want to separating the text that comes to text form field
let's say user writes 1111111 and output will be 1,111,111
Form(
child: Column(
children: [
TextFormField(
keyboardType: TextInputType.emailAddress,
decoration: InputDecoration(
labelText: 'Email Address',
hintText: 'you#example.com',
),
)
],
),
),

You should use the controller property from the TextFormField class.
You'll need to make your widget a stateful one (we'll need it's dispose method).
Add the controller to your state:
final _textController = TextEditingController();
#override
void dispose() {
super.dispose();
_textController.dispose();
}
Add a listener to your controller to format your input whenever you type:
#override
void initState() {
super.initState();
_textController.addListener(() {
// using Ashok's answer to format the text
final reg_ex = new RegExp(r'(\d{1,3})(?=(\d{3})+(?!\d))');
final matchFunc = (Match match) => '${match[1]},';
final text = _textController.text;
_textController.value = _textController.value.copyWith(
// we need to remove all the ',' from the values before reformatting
// if you use other formatting values, remember to remove them here
text: text.replaceAll(',', '').replaceAllMapped(reg_ex, matchFunc),
// this will keep the cursor on the right as you type in values
selection: TextSelection(
baseOffset: text.length,
extentOffset: text.length,
),
);
});
}
Use the controller within your TextFormField:
TextFormField(
controller: _textController,
keyboardType: TextInputType.emailAddress,
decoration: InputDecoration(
labelText: 'Email Address',
hintText: 'you#example.com',
),
)

RegExp reg_ex = new RegExp(r'(\d{1,3})(?=(\d{3})+(?!\d))');
Function mathFunc = (Match match) => '${match[1]},';
List<String> sample = [
'1111111',
];
sample.forEach((String str) {
String result = str.replaceAllMapped(reg_ex, mathFunc);
print('$str -> $result');
});

Related

Best way to validate a form with flutter provider package?

I need separate logic with UI.
I used the following example:
1.- Use a class validation item to show a string value and error.
class ValidationItem {
final String value;
final String error;
ValidationItem(this.value, this.error);
}
2.- Use the next code for provider class.
class SignupValidation with ChangeNotifier {
ValidationItem _firstName = ValidationItem(null,null);
//Getters
ValidationItem get firstName => _firstName;
bool get isValid {
if (_firstName.value != null){
return true;
} else {
return false;
}
}
//Setters
void changeFirstName(String value){
if (value.length >= 3){
_firstName=ValidationItem(value,null);
} else {
_firstName=ValidationItem(null, "Must be at least 3 characters");
}
notifyListeners();
}
void submitData(){
print("FirstName: ${firstName.value}");
}
}
3.- Use the next widget to show text field and validate
class Signup extends StatelessWidget {
#override
Widget build(BuildContext context) {
final validationService = Provider.of<SignupValidation>(context);
return Scaffold(
appBar: AppBar(
title: Text('Signup'),
),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: ListView(
children: <Widget>[
TextField(
decoration: InputDecoration(
labelText: "First Name",
errorText: validationService.firstName.error,
),
onChanged: (String value) {
validationService.changeFirstName(value);
},
),
RaisedButton(
child: Text('Submit'),
onPressed: (!validationService.isValid) ? null : validationService.submitData,
)
],
),
),
);
}
}
The problem is the performance for example every time the text is changed the notifyListener() Is calles.
My question: Is there a cost to performance?
you can use TextFormField instead of TextField.
Best way to validate fields is that you can use validator property TextFormField property as bellow
TextFormField(
decoration: InputDecoration(
labelText: "First Name",
errorText: validationService.firstName.error,
),
validator: (e){
if(e!.trim().isEmpty) return "String is empty";
return null;
},
onChanged: (String value) {
validationService.changeFirstName(value);
},
),
The TextField itself gives you the ability to validate the form, then why to make it complex by implementing notifier, instead you want to make it common you can make the validater global function for it. Nad user it in the validate function.
Void validateEmail(String value){ // your logic}
Use this function as follow
TextFormField(
decoration: InputDecoration(
labelText: "First Name",
errorText: validationService.firstName.error,
),
validator: validateEmail(),
onChanged: (String value) {
validationService.changeFirstName(value);
},
Secondly to get the value of inputted string you have a TextEditingController which directly give you the string you inputted.
Declare TextEditingController as follow
TextEditingController emailCont = TextEditingController();
Use this controller in TextField as follow
TextFormField(
controller: emailCont,
decoration: InputDecoration(
labelText: "First Name",
errorText: validationService.firstName.error,
),
validator: validateEmail(),
onChanged: (String value) {
validationService.changeFirstName(value);
},
Now to get the value from this controller you can get it this way.
emailCont.text
This way it will be easy to manage and less complexity.

TextFormField cuts last character input

I'm having a weird issue with a TextFormField, it cuts off the last input. If I type something like hello, it's gonna cut off the o and save hell. if I give it a space like hello , it's gonna save hello. Has anyone been through the same issue and know how to fix it?
here is my code:
String messageText;
_ChatScreenState() {
_formKey = GlobalKey<FormState>();
_scrollController = ScrollController();
messageText = "";
}
Widget messageTextField() {
return SizedBox(
width: deviceWidth * 0.55,
child: TextFormField(
style: TextStyle(color: Colors.white),
validator: (text) {
if (text.isEmpty) {
return 'Digite sua mensagem';
}
return null;
},
onChanged: (text) {
_formKey.currentState.save();
},
onSaved: (text) {
setState(() {
messageText = text;
});
},
cursorColor: Colors.white,
decoration: InputDecoration(
border: InputBorder.none,
hintText: 'Digite uma mensagem',
hintStyle: TextStyle(color: Colors.white.withAlpha(100))),
autocorrect: false,
),
);
}
I do not think save() is intended to be used with onChanged.
If you place a button somewhere and perform _formKey.currentState.save(); within onPressed of the button, you should see the entire text value being saved.

Flutter TextField - How to support submission on <ENTER> _and_ newline on <SHIFT-ENTER>

I'm working on a Flutter Web application which includes chat.
I'd like to include an ordinary input function where users can enter text and send it into the chat stream. A standard feature of chat apps these days is to send on <ENTER> and to perform a line break on <SHIFT-ENTER>, or some variation of this.
Currently I've only been able to achieve one of these functions at a time. If you set the TextField's keyboardType to TextInputType.multiline then <ENTER> and <SHIFT-ENTER> always perform a line-break, there doesn't appear to be a way to override this behavior.
If instead your TextField is TextInputType.text you can capture <ENTER> and send, but trying to capture <SHIFT-ENTER> to add a line-break has not worked. I've tried manually grabbing the key press via an onKey handler and inserting \n to the controller.text, but it appears that TextInputType.text is not meant for multiline at all, so it doesn't play well.
Just wondering if any other devs have run into this or come up with any suitable solutions. Ideally a solution would also work across android/ios. For me, I've decided to go with TextInputType.text and forgo the multiline functionality for now.
Thanks
For what it's worth, I was able to concoct a reasonable solution that I'll post below in case anyone runs into this themselves.
I wrapped the Textfield in a keyboard listener which calls my onSend function when it see's an <Enter>. I tried this before, but I guess earlier I was missing the cast to RawKeyEventDataWeb which allowed me to capture isShiftPressed to allow for new lines on <SHFT-ENTER> without forcing a send. Unfortunately I had to add some hacky code to remove the \n that's added when pressing enter, but that's a small price to pay for functional + modern messaging.
RawKeyboardListener(
focusNode: focusNode,
onKey: handleKeyPress,
child: TextField(
controller: messageController,
minLines: 1,
maxLines: null,
textInputAction: TextInputAction.done,
style: normalTextStyle,
keyboardType: TextInputType.multiline,
decoration: InputDecoration(
isDense: true,
hintText: 'Type a message',
hintStyle: TextStyle(
fontSize: 16,
color: Color(0xFF474749),
),
border: InputBorder.none,
),
),
)
void handleKeyPress(event) {
if (event is RawKeyUpEvent && event.data is RawKeyEventDataWeb) {
var data = event.data as RawKeyEventDataWeb;
if (data.code == "Enter" && !event.isShiftPressed) {
final val = messageController.value;
final messageWithoutNewLine =
messageController.text.substring(0, val.selection.start - 1) +
messageController.text.substring(val.selection.start);
messageController.value = TextEditingValue(
text: messageWithoutNewLine,
selection: TextSelection.fromPosition(
TextPosition(offset: messageWithoutNewLine.length),
),
);
_onSend();
}
}
}
This can be achieved by adding a FocusNode to the TextField. Place the focus node in your widget's state.
late final _focusNode = FocusNode(
onKey: (FocusNode node, RawKeyEvent evt) {
if (!evt.isShiftPressed && evt.logicalKey.keyLabel == 'Enter') {
if (evt is RawKeyDownEvent) {
_sendMessage();
}
return KeyEventResult.handled;
}
else {
return KeyEventResult.ignored;
}
},
);
In your build function add the focus when creating the TextField.
TextField(
autofocus: true,
controller: _textController,
focusNode: _focusNode,
)
This is what I am using in my TextField to support newline on enter.
class TextInputsWidget extends StatelessWidget {
final TextEditingController chatTextFieldController = TextEditingController();
late final _focusNode = FocusNode(
onKey: _handleKeyPress,
);
KeyEventResult _handleKeyPress(FocusNode focusNode, RawKeyEvent event) {
// handles submit on enter
if (event.isKeyPressed(LogicalKeyboardKey.enter) && !event.isShiftPressed) {
_sendMessage();
// handled means that the event will not propagate
return KeyEventResult.handled;
}
// ignore every other keyboard event including SHIFT+ENTER
return KeyEventResult.ignored;
}
void _sendMessage() {
if (chatTextFieldController.text.trim().isNotEmpty) {
// Do something with your input text
print(chatTextFieldController.text.trim());
// bring focus back to the input field
Future.delayed(Duration.zero, () {
_focusNode.requestFocus();
chatTextFieldController.clear();
});
}
}
#override
Widget build(BuildContext context) {
return Container(
child: TextField(
keyboardType: TextInputType.multiline,
maxLines: null,
textInputAction: TextInputAction.newline,
autofocus: true,
focusNode: _focusNode,
controller: chatTextFieldController,
decoration: const InputDecoration(
border: InputBorder.none,
contentPadding: EdgeInsets.fromLTRB(8, 0, 0, 0),
hintText: "Enter your message here",
hintStyle: TextStyle(color: Colors.black54),
),
),
);
}
}
There are mainly 3 key changes
keyboardType: TextInputType.multiline,
textInputAction: TextInputAction.newline,
FocusNode which can listen to keyboard events
The best way to have the Enter key be disabled for the input and instead send it when no ctrl key is pressed is through the focusNode directly on the input, this way you won't have to remove extra new lines.
class _InputTextState extends State<InputText> {
late final _focusNode = FocusNode(onKey: handleKeyPress);
#override
Widget build(BuildContext context) {
return TextField(
focusNode: _focusNode,
);
}
KeyEventResult handleKeyPress(FocusNode focusNode, RawKeyEvent event) {
// handles submit on enter
if (kIsWeb &&
event.isKeyPressed(LogicalKeyboardKey.enter) &&
!event.isControlPressed &&
!event.isShiftPressed) {
widget.onSubmit();
// handled means that the event will not propagate
return KeyEventResult.handled;
}
return KeyEventResult.ignored;
}
}

Flutter: Adding a hyphen and brackets to a user's phone number entered in a textfield

I am trying to rearrange a user's entered phone number with brackets around the area code and a hyphen. For example, the user would enter 9991234567 and it would be rearranged to (999) 123-4567 inside the textfield.
I'm using a RegExp to separate the user's entry into the area code, and the 2 parts of the phone number. I am attempting to use a TextEditingController to edit the text field with brackets and a hyphen when the Save button is pressed but it does not seem to work.
_saveButtonPressed() async {
RegExp phone = RegExp(r'(\d{3})(\d{3})(\d{4})');
var matches = phone.allMatches(UserProfile.instance.phone);
var match = matches.elementAt(0);
setState(() {
phoneController.text = '(${match.group(1)}) ${match.group(2)}-${match.group(3)}';
});
}
This is the code for the phone number textfield.
_makeRowForAttribute(
imageAsset: "assets/images/phone.png",
title: "PHONE NUMBER",
keyboardType: TextInputType.phone,
placeholder: "6131110123",
charLimit: 10,
initialValue: UserProfile.instance.phone,
controller: phoneController,
onSave: (phone) {
UserProfile.instance.phone = phone.toString();
},
),
You can simply use flutter_masked_text package
It's just simple as following
import 'package:flutter_masked_text/flutter_masked_text.dart';
class MobileNumberTextField extends StatefulWidget {
createState() => MobileNumberTextFieldState();
}
class MobileNumberTextFieldState extends State<MobileNumberTextField> {
final controller =MaskedTextController(mask: "(000) 000-0000");
#override
Widget build(BuildContext context) {
return TextField(
controller: controller,
keyboardType: TextInputType.number,
autofocus: true,
);
}
}
Hope it will be helpful
I think this should do the trick.
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class FormattedPhoneNumber extends StatefulWidget {
#override
_FormattedPhoneNumberState createState() => _FormattedPhoneNumberState();
}
class _FormattedPhoneNumberState extends State<FormattedPhoneNumber> {
String text = "";
convert(TextEditingValue oldValue, TextEditingValue newValue) {
print("OldValue: ${oldValue.text}, NewValue: ${newValue.text}");
String newText = newValue.text;
if (newText.length == 10) {
// The below code gives a range error if not 10.
RegExp phone = RegExp(r'(\d{3})(\d{3})(\d{4})');
var matches = phone.allMatches(newValue.text);
var match = matches.elementAt(0);
newText = '(${match.group(1)}) ${match.group(2)}-${match.group(3)}';
}
// TODO limit text to the length of a formatted phone number?
setState(() {
text = newText;
});
return TextEditingValue(
text: newText,
selection: TextSelection(
baseOffset: newValue.text.length,
extentOffset: newValue.text.length));
}
#override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: TextField(
inputFormatters: [
TextInputFormatter.withFunction(
(oldValue, newValue) => convert(oldValue, newValue)),
],
keyboardType: TextInputType.phone,
decoration: InputDecoration(
border: OutlineInputBorder(),
hintText: "input",
labelText: "Converts to phone number format"),
// Fixes a problem with text-caret only being at the start of the textfield.
controller: TextEditingController.fromValue(new TextEditingValue(
text: text,
selection: new TextSelection.collapsed(offset: text.length))),
),
),
],
);
}
}
Hope it helps :-)

Flutter update countertext

In Flutter, inputDecoration's countertext property does not change as the user is typing in the TextFormField. Is it possible to decrement the countertext as the user is typing?
TextFormField(
keyboardType: TextInputType.number,
decoration: new InputDecoration(
counterText: "9",
hintText: "Enter exact order number",
),
)
I edit this answer to work with your question
class StackEditText extends StatefulWidget {
#override
_StackEditTextState createState() => _StackEditTextState();
}
class _StackEditTextState extends State<StackEditText> {
TextEditingController _controller = new TextEditingController();
void onValueChange() {
setState(() {
_controller.text;
});
}
#override
void initState() {
super.initState();
_controller.addListener(onValueChange);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Container(
child: TextFormField(
controller: _controller,
maxLength: 9,
decoration: InputDecoration(
counterText: "${9 - _controller.text.length}",
hintText: 'Enter exact order number',
),
),
),
);
}
}
I do not recommend using the decoration: InputDecoration::counterText. You have to use setState or whatever to manually update the counter that way.
Instead, I recommend the maxLength property, that automatically makes a counter and updates it:
TextField(maxLength: 8)
Result:
This might be what most people want.
You can even further customize it with the buildCounter parameter, to return whatever widget you want when the text length changes. For example, if you only want to display how many characters left, you can do this:
TextField(
maxLength: 8,
buildCounter: (
BuildContext context, {
int currentLength,
int maxLength,
bool isFocused,
}) {
return Text('${maxLength - currentLength}');
},
)