Flutter text field value from state + on change update state - flutter

I have a text field value powered by a State variable with some calculation, I want to live calculate and update the same state variable back when user inputs value. The final result just doesnt work, text fiend input behaves strangely.
If I use onSubmitted instead of onChanged, it works well, I guess I am not in a loop of updating values back and forth from the state variable.
Any idea how can I make this happen?
myController.text = '${value.toStringAsFixed(1)}';
TextField(
onChanged: (text){
this.onValueChange(text, index);
},
controller: myController,
),
and the function onValueChange is calling to set state is this
void setValue(_value, _index){
setState((){
value =double.parse(_value)/exchangeRate["rates"][currencies[_index]];
});
}

Suppose we want to make a textfieild for OTP and submit button press once on that it display the OTP on console screen and we fill that our text field same as console

add listener to get the text field value
void initState() {
super.initState();
// update value in listener
myController.addListener(() {
setState(() {
myController.text = "your value";
});
});
}
// your textField
TextField(
controller: myController,
),

You need to use setState inside onChanged
TextField(
onChanged: (text){
setState(() {
this.onValueChange(text, index);
});
},
controller: myController,
),

Related

How to make provider listener listen only once

I am geting input(text) using textfield and displaying in a list, I am using onchanged property of textfield and provider to update the text of new element in list but, all elements in the list update to onChanged's new value, once the element is added to list I want it to stop listening to changes of onChanged. So, that I can display list with different elements. How do I achieve that.
TextField(
autofocus: true,
decoration: kTextFieldDecocation.copyWith(
hintText: 'B Name'),
onChanged: (newbName) {
Provider.of<BNameControllerClass>(context,
listen: false)
.newBorrowerName(newbName);
},
),
List element's text
Text(
Provider.of<BNameControllerClass>(context,
listen: true)
.bName,
style: const TextStyle(fontSize: 20),
);
provider class
class BNameControllerClass extends ChangeNotifier {
String bName = 'Ganesh';
newBorrowerName(String newName) {
bName = newName;
notifyListeners();
}
}
Create List<String> textsFromInput = [];
Generate text widgets with ListView.generate().
Then in TextField you can use onSubmitted: (value) => textsFromInput.add(value)
Depending on what state management you have you can then call setState() or handle list rebuilding with bloc builder buildWhen: previous.textsFromInput.length != current.textsFromInput.length or with provider.

Error when supplying an initial value to TextField

I am facing a problem with TextField, since I am working hand in hand with TextEditingController()..text and onChanged, but when entering a new data, it is not reflected in the TextField. I made a print inside the onChanged this same one recognizes a new entry but the value to initiate continues without being updated. Inside the onChanged, I have a function which is in charge of validating what is entered and returning an error if necessary. When I comment the instruction before mentioned the TextField already allows to enter and to update what the user enters.
I hope you can help me, a feedback, tutorial, etc.
I would appreciate it.
TextField Code:
CustomTextField(
controller: TextEditingController()..text = datumAdministrative.name,
placeholder: Constants.selectDate,
helperText: Constants.requiredData,
keyboardType: TextInputType.text,
enable: true,
errorText: validationForm.name.error,
textInputAction: TextInputAction.next,
textCapitalization: TextCapitalization.sentences,
onChanged: (String value) {
validationForm.changeName(value);
},
);
ValidationForm Code:
void changeName(String value) {
String pattern = r'(^[a-zA-Z ]*$)';
RegExp regExp = new RegExp(pattern);
regExp.hasMatch(value)
? _name = ValidationItem(value, null)
: _name = ValidationItem(null, Constants.nameAdministrativeMessage);
notifyListeners();
}
Try Using : TextController(text: "<Required Text>")
Also does the validation have to be every single time the user enter any word ?
If not, you can try validation everything at the end.
If you are trying to use reactive validation, make sure your CustomTextField is wrapped with the widget which is responsible for rebuilding the UI.. something like Consumer() when using provider package
The problem is probably caused because the TextEditingController object is getting discarded by the rebuilds made by Flutter because you are instantiating the TextEditingController inside a build method. You should save the instance of your controller elsewhere, like in a state object as shown by the official docs or in your case, you can create it and get it from your validationForm.
This is the example in the docs:
/// This is the private State class that goes with MyStatefulWidget.
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
/// save the [TextEditingController] instance
final TextEditingController _controller = TextEditingController();
...
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
alignment: Alignment.center,
padding: const EdgeInsets.all(6),
child: TextFormField(
controller: _controller, // User your instance
decoration: const InputDecoration(border: OutlineInputBorder()),
),
),
);
}
}
Possible solution in your case:
CustomTextField(
controller: validationForm.myTextController,
placeholder: Constants.selectDate,
...

ScrollView scrolls automatically if i set text to textfield using its controller

I have created a form using scrollview widget & when initState() method _getDataUser() is called i set some prefill controllerEmail.text to textfield which makes my scrollview to scroll to the TextFormField Email source code :
https://pastebin(dot)com/sFR7s4wS
I found a solution here, you can wrap your TextField into a Focus, and only when the user has focused on the text field we set showCursor to true.
bool showCursor = false;
Focus(
onFocusChange: (focus) => setState(() => showCursor = focus),
child: TextField(
showCursor: showCursor,
controller: _textController,
textCapitalization: TextCapitalization.words,
),
)
This is flutter's native functionality and I have programatically solved this using ScrollController and Future.delayed. Just assign your scroll view or list view to a scroll controller and do the following:
runZoned(() {
Future.delayed(Duration(seconds: 0), () {
_scrollController.jumpTo(0);
});
}, onError: (error, stackTrace) {
print('Zone Error: $error');
});

Flutter- TextEditingController listener get called multiple time for textfield

TextField controlled controller.addListener(() gets called multiple time after pressing the clear button, this will only happen if we are clearing it.
Snippet:
TextEditingController controller = new TextEditingController();
TextField field = new TextField(
controller: controller,
autofocus: true,
);
controller.addListener(() {
print("Pressed cancel button");
});
Video Link
Note: While adding characters in TextField listener method gets called only ones.
I guess that would be a defect on flutter, a possible solution would be to use onChanged()
TextField field = new TextField(
autofocus: true,
onChanged: (String value) {
print("Pressed clear button");
},
);
I have the same problem with Nexus 6p when used with API level 23 and Pixel with API 25.
but this problem did not occurs with Pixel with API28 and it does not occurs with Nexus6P with API26.
exact code from https://flutter.dev/docs/cookbook/forms/text-field-changes was used.
1. We need to create our own .clear() method
void clearField() {
print("c: clearField");
var newValue = textController.value.copyWith(
text: '',
selection: TextSelection.collapsed(offset: 0),
);
textController.value = newValue;
callApi('');
}
// and call it by :
child: TextField(
controller: textController,
autofocus: true,
decoration: InputDecoration(
suffixIcon: IconButton(
icon: Icon(Icons.close),
onPressed: clearField, // call
),
),
),
2. We need to carefully handle changes
void changesOnField() {
print("c: changesOnField");
String text = textController.text;
if (text.isNotEmpty) { // set this
callApi(text);
}
}
Full Code
You may look into this repo and build it locally Github
Result

Detect 'enter key' press in flutter

In my case i need to scan barcode and fetch product details. Normally barcode scanner devices emit enter key(keycode=13) event at end of scanning, But in flutter enter key is not same as Done so how can code to detect enter key pressed in my TextFormField widget?
if you are using TextField then you have to add onSubmitted in your text field to detect when user press Enter key. For my case, I changed Done in keyboard to TextInputAction.Search. It also works for TextInputAction.Done too. here is a sample code
TextField(
onSubmitted: (value){
//value is entered text after ENTER press
//you can also call any function here or make setState() to assign value to other variable
},
textInputAction: TextInputAction.search,
)
The solution above works, but I believe RawKeyboardListener is a more reliable and flexible solution. You just need to cover the text field with it and start to listen to keyboard events:
var focusNode = FocusNode();
RawKeyboardListener(
focusNode: focusNode,
onKey: (event) {
if (event.isKeyPressed(LogicalKeyboardKey.enter)) {
// Do something
}
},
child: TextField(controller: TextEditingController())
)
As a second option you can use onKey method of the FocusNoded and pass the node to your text field:
var focusNode = FocusNode(onKey: (node, event) {
if (event.isKeyPressed(LogicalKeyboardKey.enter)) {
// Do something
// Next 2 line needed If you don't want to update the text field with new line.
// node.unfocus();
// return true;
}
return false;
});
TextField(focusNode: focusNode, controller: TextEditingController())
In case someone is looking for the same solution (as Al Walid Ashik) but for TextFormField, just use the following:
TextFormField(
/// ...
onFieldSubmitted: (value) {
/// do some stuff here
},
),
TextFormField(
maxLines: null,
autovalidate: true,
validator: (value){
if(value.contains('\n')){
doFun(value);
}
}
)
When user press enter key new line create in text box. We check with that.
maxLine:null - to hide multiline
autovalidate:true -to automatically run validator fun
'\n' - new line ('\s'-whitespace,'\t'-tab.. etc)
In addition to the Sergey Yamshchikov's answer:
In case if it is a multiline TextField (maxLines: null) and you want to catch up the entered key and prevent passing it into the text field, you can use this approach:
RawKeyboardListener(
focusNode: FocusNode(onKey: (node, event) {
if (event.isKeyPressed(LogicalKeyboardKey.enter)) {
return KeyEventResult.handled; // prevent passing the event into the TextField
}
return KeyEventResult.ignored; // pass the event to the TextField
}),
onKey: (event) {
if (event.isKeyPressed(LogicalKeyboardKey.enter)) {
// Do something
}
},
child: TextField(controller: TextEditingController())
)
But, if you need to detect the keys combination, like ctrl+enter, then you can use CallbackShortcuts:
CallbackShortcuts(
bindings: {
const SingleActivator(LogicalKeyboardKey.enter, control: true): _doSomething(),
},
child: Focus(
autofocus: true,
child: TextField(controller: TextEditingController()),
),
);