Reputation: 3978
I create a form that container inputs. I loop through list of inputs to create form. My variable is:
List fields = [
{
'label': Strings.firstName,
'controller': _fnameController,
'validator': (val) => Validation.mustFilled(val),
},
{
'label': Strings.lastName,
'controller': _lnameController,
'validator': (val) => Validation.mustFilled(val),
},
{
'label': Strings.phoneNumber,
'controller': _mobileController,
'validator': (val) => Validation.mobile(val),
},
];
and my TextEditingController definition:
static TextEditingController _fnameController = TextEditingController();
static TextEditingController _lnameController = TextEditingController();
static TextEditingController _mobileController = TextEditingController();
I get values of inputs from previous screen and set inputs in initState:
@override
void initState() {
super.initState();
_fnameController.text = widget.userProfile.firstName;
_lnameController.text = widget.userProfile.lastName;
_mobileController.text = widget.userProfile.phoneNumber;
}
for (var item in fields)
Container(
margin: EdgeInsets.symmetric(vertical: 10.0),
child: Input(
controller: item['controller'],
label: item['label'],
validator: item['validator'],
),
),
and my Input widget:
class Input extends StatelessWidget {
final String label;
final VoidFunc validator;
final TextEditingController controller;
Input({this.label, this.validator, this.controller});
@override
Widget build(BuildContext context) {
return TextFormField(
autovalidate: true,
controller: controller,
textAlignVertical: TextAlignVertical.center,
cursorColor: ColorPalette.secondary_3_5,
decoration: InputDecoration(
filled: true,
labelText: label,
),
validator: (value) => validator(value),
);
}
}
and finally dispose them:
@override
void dispose() {
_fnameController.dispose();
_lnameController.dispose();
_mobileController.dispose();
super.dispose();
}
every thing is ok but when I navigate to previous screen (use back button) and then come to this screen again I get this error:
A TextEditingController was used after being disposed.
Once you have called dispose() on a TextEditingController, it can no longer be used.
The relevant error-causing widget was
Upvotes: 11
Views: 35533
Reputation: 179
If you are using a simple text field or text form field then don't dispose the controller and simply initialize it as follow
TextEditingController pinController = TextEditingController();
and if you are using pin code text field then it has its own property, simply use that.
PinCodeTextField(
autoDisposeControllers:false,
)
Upvotes: 4
Reputation: 54367
Please remove static
keyword from TextEditingController
Change from
static TextEditingController _fnameController = TextEditingController();
static TextEditingController _lnameController = TextEditingController();
static TextEditingController _mobileController = TextEditingController();
To
TextEditingController _fnameController = TextEditingController();
TextEditingController _lnameController = TextEditingController();
TextEditingController _mobileController = TextEditingController();
I use the following full code to reproduce this error.
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(
title: 'Navigation Basics',
home: FirstRoute(),
));
}
class FirstRoute extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('First Route'),
),
body: Center(
child: ElevatedButton(
child: Text('Open route'),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecondRoute()),
);
},
),
),
);
}
}
class SecondRoute extends StatefulWidget {
@override
_SecondRouteState createState() => _SecondRouteState();
}
class _SecondRouteState extends State<SecondRoute> {
static TextEditingController _fnameController = TextEditingController();
@override
void dispose() {
_fnameController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Second Route"),
),
body: Center(
child: ElevatedButton(
onPressed: () {
Navigator.pop(context);
},
child: Text('Go back!'),
),
),
);
}
}
Upvotes: 6
Reputation: 51
You can override the controller with an empty value by changing the value with onPressed sequence like this
onPressed: () {
setState(() {
textEditingController.text = "";
Navigator.pop(context);
Navigator.push(
context,MaterialPageRoute(
builder: (context) =>const OTPGet()));
});
}
This is good if you reload the flow of the PinCodeTextField page again. If you won't revisit the page again, Better you can use void Dispose(){} sequence on initState() {}
TextEditingController textEditingController = TextEditingController(text: "");
PinCodeTextField(
appContext: context,
autoDisposeControllers: false,
length: 6,
inputFormatters: <TextInputFormatter>[
FilteringTextInputFormatter.allow(RegExp("[0-9]")),
],
animationType: AnimationType.fade,
pinTheme: PinTheme(
borderRadius: BorderRadius.circular(10),
shape: PinCodeFieldShape.box,
activeColor: Colors.white,
selectedColor: Colors.white,
inactiveColor: Colors.white,
fieldHeight: 50,
fieldWidth: 50,
activeFillColor: Colors.white,
selectedFillColor: Colors.white,
inactiveFillColor: Colors.white),
cursorColor: Colors.black,
animationDuration: const Duration(milliseconds: 300),
enableActiveFill: true,
controller: textEditingController,
keyboardType: TextInputType.number,
onChanged: (code) {
_onOtpCallBack(code, false);
}),
TextButton(
onPressed: () async {
Navigator.pop(context);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
const OTPGet()));
setState(() {
textEditingController.text = "";
});
},
child: Text(
"resend".tr,
style: Styles.sixteenMediumWhiteTextStyle,
)),
bool _isLoadingButton = false;
bool _enableButton = false;
_onOtpCallBack(String otpCode, bool isAutofill) {
setState(() {
if (otpCode.length == _otpCodeLength) {
_enableButton = false;
_isLoadingButton = true;
_verifyOtpCode();
otp = otpCode;
} else {
_enableButton = false;
}
});
}
_verifyOtpCode() {
FocusScope.of(context).requestFocus(FocusNode());
Timer(const Duration(milliseconds: 4000), () {
setState(() {
_isLoadingButton = false;
_enableButton = false;
});
});
}
Upvotes: 0
Reputation: 627
This solution is only for the people using "pin_code_fields" dependence:
Add or change from this.autoDisposeControllers = true
to this.autoDisposeControllers = false
Hope it helps.
Upvotes: 49