I have three widgets and they are all in separate files from the "main" of these three widgets, I need to pass the controller to the button and TextFormField, but I don't understand how to do it correctly and therefore this error crashes. I also use ChangeNotifeProvide in the "main" widget.
I tried passing it like this controller: user. firstName and taking it in a widget with a TextFormField like this TextEditingController _controller = TextEditingController(text: controller) but the error was the same
"Main" widget:
class _EditDataPageState extends State<EditDataPage> {
final nameController = TextEditingController();
@override
void dispose() {
nameController.dispose();
sNameController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Consumer<UserState>(
builder: (context, user, child) => SafeArea(
top: false,
left: false,
right: false,
bottom: false,
child: Form(
key: JosKeys.keyName,
child: ListView(
children: <Widget>[
Container(
//color: Colors.red,
child: CustomFormTextField(
lengthLimiit: 16,
textContoller: nameController,
initialName:
${context.select((UserState p) => p.firstName)}',
keyboadrd: TextInputType.text),
),
SaveButton(
key: JosKeys.keyName,
typeProperty: 'name',
controller: nameController,
)
],
),
),
),
);
}
}
Widget with TextFormField
class _CustomFormTextFieldState extends State<CustomFormTextField> {
final String? initialName, typeValidate;
final TextInputType keyboadrd;
final TextEditingController textContoller;
final int lenghtLimit;
_CustomFormTextFieldState(this.initialName, this.typeValidate, this.keyboadrd,
this.textContoller, this.lenghtLimit);
@override
Widget build(BuildContext context) {
return TextFormField(
controller: textContoller,
inputFormatters: [LengthLimitingTextInputFormatter(lenghtLimit)],
initialValue: this.initialName,
keyboardType: keyboadrd,
validator: _validate,
style: TextStyle(
color: Colors.white, fontSize: 14.0, fontWeight: FontWeight.w500),
decoration: InputDecoration(
contentPadding: EdgeInsets.all(10.0),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(0)),
borderSide: BorderSide(color: Colors.white54)),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(0)),
borderSide: BorderSide(color: Colors.white54)),
),
);
}
}
The button is for saving and I need the controller there to update the data
class SaveButton extends StatelessWidget {
//Map<String, String> saveStateForm;
final GlobalKey<FormState> key;
final String typeProperty;
final TextEditingController? controller, secondContoller;
SaveButton(
{required this.typeProperty,
required this.key,
required this.controller,
@required this.secondContoller});
@override
Widget build(BuildContext context) {
void onPress() {
if (this.key.currentState!.validate()) {
if (this.typeProperty == 'phone') {
Provider.of<UserState>(context)
.updatePhone(this.controller.toString());
} else if (this.typeProperty == 'email') {
Provider.of<UserState>(context)
.updateEmail(this.controller.toString());
} else if (this.typeProperty == 'name' ||
this.typeProperty == 'sName') {
Provider.of<UserState>(context)
.updateFirstName(this.controller.toString());
if (secondContoller != null) {
Provider.of<UserState>(context)
.updateSname(this.controller.toString());
}
} else
print('TYPEPROPERTY ERROR');
}
}
You can't use initialValue and controller at the same time. So, a better way is to use controller because its constructor does provide you initial value that you can set.
Here is an example.
// In class level
final controller = TextEditingController(text: "Your initial value");
Widget build(BuildContext context) {
return TextFormField(
controller: controller,
// ...
);
}
In order to track the value entered by the user you can then use
controller.text
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With