Reputation: 2310
I'm encountering an issue with updating a variable within a StatefulWidget in Flutter. Specifically, I have a custom widget CustomErrorFormField which extends StatefulWidget. This widget contains a method setErrorList to update a list variable errorList. However, when setErrorList is called from another class, the build method in CustomErrorFormField does not reflect the updated errorList.
I understand that calling setState should trigger a rebuild of the widget, but I am unsure how to appropriately invoke setState in the StatefulWidget when the variable is updated from an external class. Here's the relevant code snippet for better understanding:
class CustomErrorFormField extends StatefulWidget {
// Variable declaration
List<String> errorList = [];
// Method to update errorList
void setErrorList(List<String> listOfError) {
errorList = listOfError;
}
@override
_CustomErrorFormFieldState createState() => _CustomErrorFormFieldState();
}
class _CustomErrorFormFieldState extends State<CustomErrorFormField> {
@override
Widget build(BuildContext context) {
// Trying to print updated errorList, but not reflecting changes
print(widget.errorList);
return ... // UI Code
}
}
In another class, I'm updating the errorList like this:
// Instance creation and update
CustomErrorFormField nameTextFild = CustomErrorFormField(...);
// Inside some method
setState(() {
// Updating errorList using setErrorList method
if (condition) {
nameTextFild.setErrorList([...]);
} else {
nameTextFild.setErrorList([...]);
}
});
Upvotes: 0
Views: 1248
Reputation: 599
It's not recommended that you change the state of a widget from outside the widget.
What you should do instead is pass the validation logic as a function
and let the widget handle the state change.
CustomFormField:
import 'package:flutter/material.dart';
class CustomErrorFormField extends StatefulWidget {
//Take the validation logic as a parameter.
final List<String> Function(String value) validator;
const CustomErrorFormField({required this.validator});
@override
_CustomErrorFormFieldState createState() {
return _CustomErrorFormFieldState();
}
}
class _CustomErrorFormFieldState extends State<CustomErrorFormField> {
//Keep the state inside the widget itself
List<String> errorList = [];
//Update the state from inside the widget
void setErrorList(List<String> listOfError) {
setState(() {
errorList = listOfError;
});
}
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
return Form(
child: TextFormField(
validator: (String value){
//Use the validation logic to decide the error.
setErrorList(widget.validator(value))
}
}
),
);
}
}
I have used TextFormField
as an example, you can use any widget that accepts a callback
upon change.
If you're making everything from scratch you can attach the validator
function to a callback
that fires when the text is changed. Usually this is done with the help of a controller
.
usage:
final nameTextFild = CustomErrorFormField(
key: ValueKey(count),
labelName: "Name",
iContext: context,
validator: (String value) {
if (!value.contains(RegExp(r'[0-9]'))) {
return [];
} else {
return ["Invalid characters, use letters only."];
}
},
);
Upvotes: 1