-
Notifications
You must be signed in to change notification settings - Fork 26.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Textfield in gallery gets reset if scrolled out of view #11500
Comments
@Hixie did some work around keeping alive offscreen widgets in scroll views. Its possible the gallery example is just missing the proper calls. |
Yeah, my TextEditorController proposition was mostly based on this discussion: https://stackoverflow.com/questions/45240734/flutter-form-data-disappears-when-i-scroll |
Hi everyone, we are experiencing same behavior with TextFormFiled as well as ExpansionTile widgets - when scrolled off screen in a ListView, both lose state. @eseidelGoogle , could you point us at the code @Hixie may have touched (in regards to "keeping alive offscreen widgets") that may need fixing? Cheers! |
|
Creating a TextEditorController only works with TextFormFields. A more generic solution is needed for other FormField derivations. |
I've posted one approach to this on the discussion board: Flutter Form persistence + example RadioTile FormField derivation |
(It would be much more convenient if the patches you wanted people to review were online e.g. on GitHub rather than in a zip file that had to be locally uncompressed, opened, etc.) |
This is worse than I thought. Turns out that if a field is hidden (deleted), 'onSave()' doesn't get called, either, nor does any supplied validator function (because it's deleted -- the Form class doesn't know anything about it, anymore.) For the 'onSave()' issue, the answer is to get values from a persister mechanism and not supply an 'onSave()' function. I suspect the validator issue will require a similar approach. The question is how to forward error state when the field gets re-instantiated. My working example repo that supplies a persister mechanism is here: https://github.com/rickbsgu/rbtile_formfield_demo.git. Note that it pulls https://github.com/rickbsgu/form_fields.git as a dependency. |
Ok, I came up with a solution to make sure a FormField validator() is called when a FormField instance is re-instantiated. The FormField checks the owning Form autostate value (which persists across FormField drops and re-instantiations) and calls the validator directly if it's set. Unfortunately, I can't make that work with TextFormField, so I cloned it and created a working version as TextInputFormField with the check and validation call in the builder call. So, this solution keeps the validator with the field, rather than having to create yet another level of indirection by having to place it in the persister. With all that, I finally seem to have a Form that behaves as I would expect it to. |
So, thinking more on this, I would suggest what is needed is a class that encapsulates all of this - something like 'FormPage' or 'FormView'. It would contain a form and the persisters (and perhaps a FocusNode). If the whole thing were self-contained, it would be much easier for users (me :) )to deal with. |
Hi there, but, i am not so sure if this is of any help to you but obviously this should happen whenever a state builds the TextFormField. Please, do let me know if you have any more suggestions or any other way to solve this issue. |
The problem when i use controller for TextFormField, it create another issue with all repos containing a form inside a listview. 1> Fill the first field "Name".
I have exactly the same behavior inside my own project. Do you have any ideas or workaround please ? |
is there any progress on this topic? |
One workaround is to maintain the TextEditingControllers for all the text fields, and make sure you reuse the same one each time for the same text field. Another would be to liberally apply KeepAlive to the widgets you want to keep alive. |
How can one create TextEditingControllers if using a map to create the form fields dynamically. |
hi @vazad28 , can you please elaborate on what you are trying to achieve? As i am not sure 'using a map to create the form fields dynamically'. Many Thanks, |
Hey, @toregua , have you got to solve the problem? One workaround is to use the SingleChildScrollView with child as Column and include all your widgets in it then you might overcome this Many thanks, |
this is what I'm trying List<Widget> getTemplateFields() {
List<Widget> _fieldWidgets = new List();
for(var idx = 0; idx < _templateFieldList.length; idx++){
switch (_templateFieldList[idx].type) {
case 'text':
_fieldWidgets.add(new ListTile(
title: new TextFormField(
keyboardType: TextInputType.text,
style: Theme.of(context).textTheme.subhead,
//labelText: globals.capitalize(_templateFieldList[idx].title),
initialValue:
_caseData.fieldsData[_templateFieldList[idx].slug] ?? '',
validator: (val){
if(_autovalidate) formValidator.validateAlphaNum(val);
_caseData.fieldsData[_templateFieldList[idx].slug] = val;
},
onSaved: (newVal) => setState(() => _caseData
.fieldsData[_templateFieldList[idx].slug] = newVal)),
));
break;
case 'number':
_fieldWidgets.add(new KeepAlive(
key: new Key(_templateFieldList[idx].slug),
keepAlive: true,
child : new TextFormField(
keyboardType: TextInputType.number,
style: Theme.of(context).textTheme.subhead,
controller: hasController[idx],
// initialValue:
// _caseData.fieldsData[_templateFieldList[idx].slug] ?? '',
decoration: new InputDecoration(
labelText: globals.capitalize(_templateFieldList[idx].title)),
validator: (val){
print("validate val $val");
if(_autovalidate) formValidator.validateNumber(val);
_caseData.fieldsData[_templateFieldList[idx].slug] = val;
},
onSaved: (newVal) => setState(() => _caseData
.fieldsData[_templateFieldList[idx].slug] = newVal)),
));
break;
case 'date':
_fieldWidgets.add( new ListTile(
title: new TextFormField(
keyboardType: TextInputType.datetime,
style: Theme.of(context).textTheme.subhead,
initialValue:
_caseData.fieldsData[_templateFieldList[idx].slug] ?? '',
decoration: new InputDecoration(
labelText: globals.capitalize(_templateFieldList[idx].title)),
validator: formValidator.validateString,
onSaved: (newVal) => setState(() => _caseData
.fieldsData[_templateFieldList[idx].slug] = newVal)),
));
break;
....... |
Hi @vazad28 , I think you can just have a list for TextEditingControllers as well just like you did for the textfields. |
I tried that too but value of the field still gets lost. |
oh sorry just use the textfield not the textformfield then you will be fine. |
With textField alone, I can's use validator. Can I? |
yesyou can use validators as well its only a call back and you can do this in onChanged value new TextField(
controller: _nameController,
focusNode: _nameFocusNode,
keyboardType: TextInputType.text,
autocorrect: false,
decoration: new InputDecoration(
labelText: 'Name *',
errorText: _nameFieldErrorText,
),
onChanged: (String value) {
if (!mounted) return;
setState(() {
(value.length > 0)
? _formWasEdited = true
: _formWasEdited = false;
customerDetailsModel.setCustomerName(value.trim());
var str = validateName(value);
(str == null)
? _nameFieldErrorText = null
: _nameFieldErrorText = str;
if (widget.borrowerSnapShot.isNotEmpty) {
(existingCustomerName.trim() ==
_nameController.text.trim())
? nameEdited = false
: nameEdited = true;
}
});
if (!(_nameController.text.isEmpty)) {
_formWasEdited = true;
}
},
),
String validateName(String value) {
// bool _formWasEdited = true;
if (value.isEmpty) return 'Name is required.';
final RegExp nameExp = new RegExp(r'^[A-Za-z ]+$');
if (!nameExp.hasMatch(value))
return 'Please enter only alphabetical characters and spaces.';
if (value.length > 25) {
return 'Name cannot exceed 25 characters';
}
return null;
} make sure you initialize the |
What's the latest on this issue? Is there a workaround until it's solved? Is the PR #15484 in the beta branch yet? Does it fix this? Or does it help a workaround of always providing an initial value? |
@acidjazz - PR #15484 was on version 2.8 (and later) of the beta branch: https://flutter.io/sdk-archive/#linux |
I've been trying to use PR #15484 as a solution to my inputs disappearing and reseting: Above in my State class.. final List<TextEditingController> _controllers = new List.generate(5, (int n) {
return new TextEditingController(); One of my TextFormField's: new TextFormField(
decoration: const InputDecoration(
icon: const Icon(Icons.computer),
labelText: 'FTP Host',
),
validator: _validateField,
initialValue: user.ftpHost,
keyboardType: TextInputType.url,
onSaved: (String value) {
user.ftpHost = value;
},
controller: _controllers[0],
) I keep getting
Exception
|
Hi Kevin,
I’ve actually described a workaround for this problem here #11500
instead of ListView use the SingleChildScrollView and use a Column as Child to include all your widgets inside the Column
just have a look at the advice given to @vazad28 and see if that helps you.
Regards,
Mahi K,
Mobile Technology Solutions Lead,
Prayuta Technologies Private Limited,
Mobile: +91-7729882000.
…On 16 May 2018, 12:41 AM +0530, kevin olson ***@***.***>, wrote:
I've been trying to use PR #15484 as a solution to my inputs disappearing and reseting:
Above in my State class..
final List<TextEditingController> _controllers = new List.generate(25, (int n) {
return new TextEditingController();
One of my TextFormField's:
new TextFormField(
decoration: const InputDecoration(
icon: const Icon(Icons.computer),
labelText: 'FTP Host',
),
validator: _validateField,
initialValue: user.ftpHost,
keyboardType: TextInputType.url,
onSaved: (String value) {
user.ftpHost = value;
},
controller: _controllers[0],
)
I keep getting
'package:flutter/src/material/text_form_field.dart': Failed assertion: line 72 pos 15: 'initialValue == null || controller == null': is not true.
Exception
I/flutter ( 8385): ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
I/flutter ( 8385): The following assertion was thrown building Settings(dirty, state: SettingsState#47968):
I/flutter ( 8385): 'package:flutter/src/material/text_form_field.dart': Failed assertion: line 72 pos 15: 'initialValue
I/flutter ( 8385): == null || controller == null': is not true.
I/flutter ( 8385):
I/flutter ( 8385): Either the assertion indicates an error in the framework itself, or we should provide substantially
I/flutter ( 8385): more information in this error message to help you determine and fix the underlying cause.
I/flutter ( 8385): In either case, please report this assertion by filing a bug on GitHub:
I/flutter ( 8385): https://github.com/flutter/flutter/issues/new
I/flutter ( 8385):
I/flutter ( 8385): When the exception was thrown, this was the stack:
I/flutter ( 8385): #2 new TextFormField (package:flutter/src/material/text_form_field.dart)
I/flutter ( 8385): #3 SettingsState.build (package:maxanet_uploader/pages/settings.dart:103:21)
I/flutter ( 8385): #4 StatefulElement.build (package:flutter/src/widgets/framework.dart:3722:27)
I/flutter ( 8385): #5 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3634:15)
I/flutter ( 8385): #6 Element.rebuild (package:flutter/src/widgets/framework.dart:3487:5)
I/flutter ( 8385): #7 BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2234:33)
I/flutter ( 8385): #8 _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding&PaintingBinding&RendererBinding&WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:626:20)
I/flutter ( 8385): #9 _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding&PaintingBinding&RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:208:5)
I/flutter ( 8385): #10 _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:990:15)
I/flutter ( 8385): #11 _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:930:9)
I/flutter ( 8385): #12 _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:842:5)
I/flutter ( 8385): #13 _invoke (dart:ui/hooks.dart:120:13)
I/flutter ( 8385): #14 _drawFrame (dart:ui/hooks.dart:109:3)
I/flutter ( 8385): (elided 2 frames from class _AssertionError)
I/flutter ( 8385): ════════════════════════════════════════════════════════════════════════════════════════════════════
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub, or mute the thread.
|
thanks @Mahender-Prayuta that worked perfectly! Here is a sample of your solution so the next person w/ this issue can resolve it faster. ...
body: new Form(
key: _formKey,
child: new Container(
padding: new EdgeInsets.symmetric(horizontal: 30.0, vertical: 30.0),
child: SingleChildScrollView(
child: new Column(
children: <Widget>[
new TextFormField(
decoration: const InputDecoration(
icon: const Icon(Icons.computer),
labelText: 'FTP Host',
),
validator: _validateField,
initialValue: user.ftpHost,
keyboardType: TextInputType.url,
onSaved: (String value) {
user.ftpHost = value;
},
),
new TextFormField(
decoration: const InputDecoration(
icon: const Icon(Icons.account_box),
labelText: 'FTP Username',
),
validator: _validateField,
initialValue: user.ftpUsername,
keyboardType: TextInputType.url,
onSaved: (String value) {
user.ftpUsername = value;
},
),
... |
cc @HansMuller did we fix this for the gallery? |
Yes, the original Gallery bug (per the bug's description) was fixed with #15484 |
@Mahender-Prayuta I solve this problem use SingleChildScrollView ,this is easy way to solve this problem. |
@Mahender-Prayuta You are awsome 😄 👍 |
@Mahender-Prayuta Thank you very vey very much. |
Is this being fixed as I'm still having this issue on the stable channel. For now I'm using @Mahender-Prayuta solution. |
I've facing this issue, solved replacing ListView to a SingleChildScrollView as suggested by @Mahender-Prayuta |
This issue is not yet fixed? It has been 3 years..... I encountered it today, and used |
Adding
https://api.flutter.dev/flutter/widgets/AutomaticKeepAliveClientMixin-mixin.html |
If you still have the problem. Or for those who are facing it recently: You need to save your state before the list view recicle the textfields.
|
This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of |
Steps to Reproduce
--> The first field is reset
As a solution I think adding a TextEditingController to the fields might suffice.
Logs
No notable logs
Flutter Doctor
Steps:
![flutter_01](https://user-images.githubusercontent.com/1158039/28914350-a3f3e4fa-783b-11e7-807a-512641d33504.png)
![flutter_02](https://user-images.githubusercontent.com/1158039/28914351-a3f5317a-783b-11e7-9944-e262d1637a2d.png)
![flutter_03](https://user-images.githubusercontent.com/1158039/28914352-a3f591ba-783b-11e7-929a-a0062ee6bdf5.png)
The text was updated successfully, but these errors were encountered: