I have a TextFormField with a controller. In this controller the initial value is 0, but the user can add decrease the number. This is the code:
TextFormField(
controller: _controller,
keyboardType: TextInputType.number,
textAlign: TextAlign.center,
onChanged: (value) {
_setQuantity();
setState(() {
quantidade = int.tryParse(_controller.text);
});
},
inputFormatters: [
FilteringTextInputFormatter.digitsOnly,
LengthLimitingTextInputFormatter(4),
],
style: TextStyle(
color: Colors.white,
fontSize: 22.0,
),
cursorColor: AppColorSecondary,
decoration: InputDecoration(
filled: true,
fillColor:
Colors.white,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10.0),
borderSide: BorderSide(color: Colors.transparent),
),
),
),
The Controller:
void _setQuantity() {
Provider.of<Product>(context, listen: false).setQuantity(
int.tryParse(_controller.text));
}
#override
void initState() {
_controller = TextEditingController(text: getSize().toString());
_controller.addListener(_setQuantity);
quantity = widget.size.quantity;
super.initState();
}
So, for example, the initial value of the TextFormField is 0, if I put 3 it keep the first zero:
// How it is now
// Initial State:
// 0
// I put a three:
// 03
//How I want:
// Initial State:
// 0
// I put a three:
// 3
How can I reach this?
onChanged:(value){
if (value[0] =="0") controller.text = value.substring(1);
}
Related
I have 1 functionality of adding TextFormField in Container on Button press upto 4 TextFormField like below image and when there's no text in TextFormField i want to remove that TextFormField so i have put that login in onChange.
When i press the button 1s time and it will add TextFormField and without typing any character if i press delete button from keyboard onChange is not getting called.
Please see this video: https://drive.google.com/file/d/1Yln48d5JHvvYdb4LRDXxmlzPzlC__xYq/view?usp=sharing
Here is my code.
TextFormField(
controller: bullet2Controller,
focusNode: focusNode2,
maxLines: null,
minLines: 1,
textCapitalization:TextCapitalization.sentences,
cursorColor: Colors.black,
showCursor: true,
autofocus: true,
textAlign: TextAlign.start,
inputFormatters: [LengthLimitingTextInputFormatter(140),],
onChanged: (value) {
setState(() {
if (value.isEmpty) {
isBullet2Visible = false;
if (isBullet1Visible) {
focusNode1.requestFocus();
} else if (isBullet3Visible) {
focusNode3.requestFocus();
} else if (isBullet4Visible) {
focusNode4.requestFocus();
} else {
FocusScope.of(context).unfocus();
}
if (_counter > 0) {
_counter--;
}
}
if (kDebugMode) {
print("${value.length.toString()} character(s)");
}
});
},
decoration: const InputDecoration(disabledBorder:
InputBorder.none,
border:
InputBorder.none,
filled: true,
fillColor: Colors.white,
),
keyboardType:
TextInputType
.multiline,
textInputAction:
TextInputAction.done,
),
Is it default behaviour or do i need to do any extra step to make it work.
this is a default behaviour.
when your value = '' and you press delete it is still equal to '' and onChanged not getting called.
to achieve your goals you should use a listener like RawKeyboardListener
Thanks to Vladyslav Ulianytskyi suggestion.
I have done this with the use of RawKEyboardListner. Here is the sample code.
RawKeyboardListener(
autofocus: true,
onKey: (event) {
setState(() {
if (event.isKeyPressed(LogicalKeyboardKey.backspace)) {
print("Perform Your Action");
}
});
},
focusNode: FocusNode(),
child: TextFormField(controller: bullet2Controller,
focusNode: focusNode2,
maxLines: null,
minLines: 1,
textCapitalization: TextCapitalization.sentences,
cursorColor: Colors.black,
showCursor: true,
autofocus: true,
textAlign: TextAlign.start,
inputFormatters: [LengthLimitingTextInputFormatter(140),
],
decoration: const InputDecoration(
disabledBorder: InputBorder.none,
border: InputBorder.none,
filled: true,
fillColor: Colors.white,
),
keyboardType: TextInputType.multiline,
textInputAction: TextInputAction.done,
),
),
)
You can try it will below code hope it's work for you
TextEditingController bullet2Controller = TextEditingController();
int currentTextLength = 0;
TextFormField(
maxLines: null,
controller: bullet2Controller,
decoration: InputDecoration(
hintText: 'Type your observations'
),
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w300,
fontFamily: 'Roboto'
),
onChanged: (String newText){
if (newText != ''){
if(newText[0] != '•'){
newText = '• ' + newText;
bullet2Controller.text = newText;
bullet2Controller.selection = TextSelection.fromPosition(TextPosition(offset: bullet2Controller.text.length));
}
if(newText[newText.length - 1] == '\n' && newText.length > currentTextLength){
bullet2Controller.text = newText + '• ';
bullet2Controller.selection = TextSelection.fromPosition(TextPosition(offset: bullet2Controller.text.length));
}
currentTextLength = bullet2Controller.text.length;
}
}
)
let me know if it's work for you or let me know if there any question.
I have multiple TextFormField in ListView.
List<TextEditingController>? notes = [];
List<TextEditingController>? notesMask = [];
List<TextEditingController>? remark = [];
List<TextEditingController>? remarkMask = [];
and below is the TextFormField inside ListView.
TextFormField(
controller: notes![index],
onChanged: (value) {
if (notes1Mask![index] != value) {
isButtonEnable = true;
} else {
isButtonEnable = false;
}
},
decoration: InputDecoration(
border: InputBorder.none,
contentPadding:
const EdgeInsets.all(10.0),
fillColor: Colors.white,
filled: true,
hintText: 'Catatan',
hintStyle: TextStyle(
color: const Color(0xFFc0c0c0)
.withOpacity(1)),
),
style: const TextStyle(
fontSize: 14,
color: Color(0xFF5E5E5E)),
),
TextFormField(
controller: remark![index],
onChanged: (value) {
if (notes1Mask![index] != value) {
isButtonEnable = true;
} else {
isButtonEnable = false;
}
},
decoration: InputDecoration(
border: InputBorder.none,
contentPadding:
const EdgeInsets.all(10.0),
fillColor: Colors.white,
filled: true,
hintText: 'Catatan',
hintStyle: TextStyle(
color: const Color(0xFFc0c0c0)
.withOpacity(1)),
),
style: const TextStyle(
fontSize: 14,
color: Color(0xFF5E5E5E)),
),
My question, How to get value from TextEditingController in ListView?
I tried print(notes), I got this result:
[TextEditingController#d4602(TextEditingValue(text: ┤Persiapan Sholat Shubuh 2 rokaats├, selection: TextSelection.collapsed(offset: 33, affinity: TextAffinity.downstream, isDirectional: false), composing: TextRange(start: -1, end: -1))),
As the result, you are getting is list of TextEditingController because List<TextEditingController>? notes = [];. To get text from it, you can do looping,
if (notes == null) return;
for (final noteController in notes!) {
print(noteController.text);
}
To get notes text as List, you can use
List<String>? notesText =
notes?.map((controller) => controller.text).toList();
More about TextEditingController
I'm trying to make Sign Up pages so I used Page View like this
page view controller.nextPage(....,...)
page view controller.prev page(....,...)
Boom Value in the Text Form Field is gone.
And this thing happens on all pages when I move to a new page in the page view and return to the page. The information that the user filled in is gone from the fields and has become empty!
why?
Form(
key: EmailKeys.formKey,
child: Column(
children: [
const Text(
"Create an account, It's free",
textAlign: TextAlign.center,
style: TextStyle(fontSize: 16, color: Colors.grey),
),
const SizedBox(
height: 40,
),
TextFormField(
onFieldSubmitted: (val) {
EmailKeys.formKey.currentState!.setState(() {
email = val.trim();
});
EmailKeys.formKey.currentState!.save();
},
textInputAction: TextInputAction.done,
inputFormatters: [LengthLimitingTextInputFormatter(100)],
obscureText: false,
keyboardType: TextInputType.emailAddress,
decoration: InputDecoration(
labelText: "Email Address",
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(15),
),
labelStyle: TextStyle(color: Colors.grey[400]),
floatingLabelStyle:
const TextStyle(color: Colors.blueGrey, fontSize: 18),
),
validator: (value) {
if (value!.isEmpty) {
return 'Email address is required';
} else if (!value.contains("#")) {
return "Email address should contain ' # ' symbol";
}
},
onChanged: (value) {
email = value.trimLeft();
},
onSaved: (val) {
setState(() {
email = val!;
});
print(email);
},
controller: _emailCtrl,
),
],
),
),
Use TexEditingController in TextFormField to hold and retrieve data https://api.flutter.dev/flutter/widgets/TextEditingController-class.html
/// This is the private State class that goes with MyStatefulWidget.
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
final TextEditingController _controller = TextEditingController();
#override
void initState() {
super.initState();
_controller.addListener(() {
final String text = _controller.text.toLowerCase();
_controller.value = _controller.value.copyWith(
text: text,
selection:
TextSelection(baseOffset: text.length, extentOffset: text.length),
composing: TextRange.empty,
);
});
}
#override
void dispose() {
_controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
alignment: Alignment.center,
padding: const EdgeInsets.all(6),
child: TextFormField(
controller: _controller,
decoration: const InputDecoration(border: OutlineInputBorder()),
),
),
);
}
}
I am developing a flutter e_commerce app, and in registration, the username should be unique, for that, we have an endpoint in API to check either the username is taken or not, my problem is with validation, I need to validate after user interaction, in flutter we have auto validate mode, but there is only(always, onUserInteraction) options, and I need the validation right after user interaction
The textFormField of the username input is
TextFormField(
cursorColor: Theme.of(context).primaryColor,
autovalidateMode: AutovalidateMode.onUserInteraction,
decoration: InputDecoration(
suffixIcon: SuffixIcon(),
labelText:
'Choose suitable name and relevant to your products',
hintText: 'SweetCandies',
labelStyle: TextStyle(color: Colors.black),
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(
color: Theme.of(context).primaryColor,
),
),
),
validator: (value) {
if(value!.isNotEmpty){}
Provider.of<Store>(context).usernameExistence(value, 'no');
if(Provider.of<Store>(context).nameExistence){
return 'The Chosen name is already taken';
}
if (value.isEmpty) {
return 'Required';
}
},
onSaved: (value) {
Provider.of<Store>(context, listen: false)
.storeInformation['name'] = value!;
},
)
is there any way to active validator after user interaction???
You can attach a focusNode to TextField so whenever focus changes you can make an api call and validate the text
add this code and initState to your code
TextEditingController controller = TextEditingController();
FocusNode focusNode;
bool _hasInputError;
String errorText = "";
String text;
#override
void initState() {
super.initState();
focusNode = new FocusNode();
focusNode.addListener(() {
if (!focusNode.hasFocus) {
setState(() {
if(Provider.of<Store>(context).nameExistence){// your condition
_hasInputErro = true;
errorText = 'The Chosen name is already taken';
}// <-- else if condition ...
else{
_hasInputErro = false;
}
});
}
});
}
in TextFormField :
TextFormField(
focusNode: focusNode,// <-- add focusNode here
controller: controller,// <-- add controller here
cursorColor: Theme.of(context).primaryColor,
autovalidateMode: AutovalidateMode.onUserInteraction,
decoration: InputDecoration(
errorText: _hasInputError ? errorText : null, // <-- add this line to show errors
suffixIcon: SuffixIcon(),
labelText:
'Choose suitable name and relevant to your products',
hintText: 'SweetCandies',
labelStyle: TextStyle(color: Colors.black),
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(
color: Theme.of(context).primaryColor,
),
),
),
// validator: ... , // <-- comment validator
onSaved: (value) {
Provider.of<Store>(context, listen: false)
.storeInformation['name'] = value!;
},
)
i want to have a textFieldInput with border that has label inside the border like the image below. Thankyou in advance
TextField(
decoration: InputDecoration(
filled: true,
fillColor: Colors.white,
labelText: "Label",
hintText: "Input Text",
contentPadding: EdgeInsets.fromLTRB(32, 16, 32, 16),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
),
),
),
Result:
I think you want to achieve something like this.
Inactive
Active
Validation
You can achieve this design by using this widget.
class OutlineBorderTextFormField extends StatefulWidget {
FocusNode myFocusNode;
TextEditingController tempTextEditingController;
String labelText;
TextInputType keyboardType;
bool autofocus = false;
TextInputAction textInputAction;
List<TextInputFormatter> inputFormatters;
Function validation;
bool checkOfErrorOnFocusChange = false;//If true validation is checked when evre focus is changed
#override
State<StatefulWidget> createState() {
// TODO: implement createState
return _OutlineBorderTextFormField();
}
OutlineBorderTextFormField(
{#required this.labelText,
#required this.autofocus,
#required this.tempTextEditingController,
#required this.myFocusNode,
#required this.inputFormatters,
#required this.keyboardType,
#required this.textInputAction,
#required this.validation,
#required this.checkOfErrorOnFocusChange});
}
class _OutlineBorderTextFormField extends State<OutlineBorderTextFormField> {
bool isError = false;
String errorString = "";
getLabelTextStyle(color) {
return TextStyle(
fontSize: 12.0, color: color
);
} //label text style
getTextFieldStyle() {
return TextStyle(
fontSize: 12.0,
color: Colors.black,
);
} //textfield style
getErrorTextFieldStyle() {
return TextStyle(
fontSize: 10.0,
color: Colors.red,
);
}// Error text style
getBorderColor(isfous) {
return isfous
? Colors.deepPurple
: Colors.black54;
}//Border colors according to focus
#override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.only(left: 16.0, top: 15.0, right: 16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
FocusScope(
child: Focus(
onFocusChange: (focus) {
//Called when ever focus changes
print("focus: $focus");
setState(() {
getBorderColor(focus);
if (widget.checkOfErrorOnFocusChange &&
widget
.validation(widget.tempTextEditingController.text)
.toString()
.isNotEmpty) {
isError = true;
errorString = widget
.validation(widget.tempTextEditingController.text);
} else {
isError = false;
errorString = widget
.validation(widget.tempTextEditingController.text);
}
});
},
child: Container(
padding: EdgeInsets.all(2.0),
decoration: BoxDecoration(
color: Colors.grey[200],
borderRadius: BorderRadius.all(Radius.circular(
6.0) // <--- border radius here
),
border: Border.all(
width: 1,
style: BorderStyle.solid,
color: isError
? Colors.red
: getBorderColor(widget.myFocusNode.hasFocus),
)),
child: TextFormField(
focusNode: widget.myFocusNode,
controller: widget.tempTextEditingController,
style: getTextFieldStyle(),
autofocus: widget.autofocus,
keyboardType: widget.keyboardType,
textInputAction: widget.textInputAction,
inputFormatters: widget.inputFormatters,
validator: (string) {
if (widget
.validation(widget.tempTextEditingController.text)
.toString()
.isNotEmpty) {
setState(() {
isError = true;
errorString = widget
.validation(widget.tempTextEditingController.text);
});
return "";
} else {
setState(() {
isError = false;
errorString = widget
.validation(widget.tempTextEditingController.text);
});
}
return null;
},
decoration: InputDecoration(
labelText: widget.labelText,
labelStyle: isError
? getLabelTextStyle(
Colors.red)
: getLabelTextStyle(Colors.deepPurple),
contentPadding:
EdgeInsets.symmetric(vertical: 7, horizontal: 16),
fillColor: Colors.grey[200],
filled: true,
enabledBorder: InputBorder.none,
errorBorder: InputBorder.none,
border: InputBorder.none,
errorStyle: TextStyle(height: 0),
focusedErrorBorder: InputBorder.none,
disabledBorder: InputBorder.none,
focusedBorder: InputBorder.none,
hasFloatingPlaceholder: true),
),
),
),
),
Visibility(
visible: isError ? true : false,
child: Container(
padding: EdgeInsets.only(left: 15.0, top: 2.0),
child: Text(
errorString,
style: getErrorTextFieldStyle(),
))),
],
),
);
;
}
}
Example for calling this widget
class _MyHomePageState extends State<MyHomePage> {
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
FocusNode myFocusNode = new FocusNode();
TextEditingController tempTextEditingController = TextEditingController();
FocusNode myFocusNode1 = new FocusNode();
TextEditingController tempTextEditingController1 = TextEditingController();
void validateAndSave() {
final FormState form = _formKey.currentState;
if (form.validate()) {
print('Form is valid');
} else {
print('Form is invalid');
}
}
String getTempIFSCValidation(String text) {
return text.length > 5 ? "* Please enter valid IFSC Code" : "";
}
String getTempAccountValidation(String text) {
return text.length > 8 ? "* Please enter valid Account Number" : "";
}
#override
Widget build(BuildContext context) {
// This method is rerun every time setState is called, for instance as done
// by the _incrementCounter method above.
//
// The Flutter framework has been optimized to make rerunning build methods
// fast, so that you can just rebuild anything that needs updating rather
// than having to individually change instances of widgets.
return Scaffold(
appBar: AppBar(
// Here we take the value from the MyHomePage object that was created by
// the App.build method, and use it to set our appbar title.
title: Text(widget.title),
),
body: Form(
key: _formKey,
child: Column(
children: <Widget>[
OutlineBorderTextFormField(labelText: "Account Number*",myFocusNode: myFocusNode,tempTextEditingController: tempTextEditingController,
keyboardType: TextInputType.number,
textInputAction: TextInputAction.next,
autofocus: false,
checkOfErrorOnFocusChange: true,
inputFormatters: [
LengthLimitingTextInputFormatter(18),
WhitelistingTextInputFormatter.digitsOnly
],
validation: (textToValidate){
return getTempAccountValidation(textToValidate);
},),
OutlineBorderTextFormField(labelText: "Re- Enter Account Number*",myFocusNode: myFocusNode1,tempTextEditingController: tempTextEditingController1,
keyboardType: TextInputType.number,
textInputAction: TextInputAction.next,
autofocus: false,
checkOfErrorOnFocusChange: true,
inputFormatters: [
LengthLimitingTextInputFormatter(18),
WhitelistingTextInputFormatter.digitsOnly
],
validation: (textToValidate){
print("Value Validated");
return getTempIFSCValidation(textToValidate);
},),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: validateAndSave,//call the validation method
tooltip: 'Validate',
child: Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}