I have called setState() to update the objects of the class MyErrorBox, but Flutter does not run the build function for those objects. I am new to Flutter and coding in general. The MyText class in the code below is just a modified TextField and MySubmit is simply a button (newFunc is the function passed in).
Here is the code for the first file (with unimportant pieces cut out):
//assume proper imports
class CreateAccountWidget extends StatefulWidget {
static List<String> errorMessages = [];
const CreateAccountWidget({super.key});
@override
State<CreateAccountWidget> createState() => _CreateAccountWidgetState();
static void updateErrorM(List<String> erm) {
errorMessages = erm;
print(errorMessages);
}
}
class _CreateAccountWidgetState extends State<CreateAccountWidget> {
//these editors control each of the textboxes
TextEditingController editor1 = TextEditingController();
TextEditingController editor2 = TextEditingController();
TextEditingController editor3 = TextEditingController();
//em is the list of error messages in the form of Strings
static List<String> em = [];
List<MyErrorBox> errors = [];
List<MyErrorBox> possibleErrs = [
MyErrorBox(whichError: 0, key: ValueKey("error1")),
MyErrorBox(whichError: 1, key: ValueKey("error2")),
MyErrorBox(whichError: 2, key: ValueKey("error3")),
MyErrorBox(whichError: 3, key: ValueKey("error4"))
];
@override
Widget build(BuildContext context) {
return Scaffold(
body: SingleChildScrollView(
child: Stack(
children: [
Column(
mainAxisSize: MainAxisSize.min,
children: [
MyText(c: editor1, h: "Enter a username", o: false),
MyText(c: editor2, h: "Enter a password", o: true),
MyText(c: editor3, h: "Confirm password", o: true),
MySubmit(
ht: "btn7",
newFunc: () {
updateErrors(); // calling update errors here to rebuild screen
if (errors.isEmpty) {
FirebaseAuth.instance.createUserWithEmailAndPassword(
email: editor1.text, password: editor2.text);
Navigator.pushReplacementNamed(context, '/login');
}
},
),
],
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: errors, //this is where the errors are displayed
),
)
],
),
),
);
}
//this is where I update the errors (and where I think the problem is)
void updateErrors() {
errors = [];
em = [];
print("");
print("NEW UPDATE ERROR----------------------------");
if (editor2.text != editor3.text) {
em.add("Confirmed password must match");
}
if (editor1.text.isEmpty) {
em.add("The username field cannot be empty");
}
if (editor2.text.isEmpty) {
em.add("The password field cannot be empty");
}
if (editor1.text.length < 8) {
em.add("The username must be at least 8 letters");
}
for (int i = 0; i < em.length; i++) {
errors.add(possibleErrs[i]);
}
setState(() {
CreateAccountWidget.updateErrorM(em);
});
print("");
}
}
class MyErrorBox extends StatefulWidget {
final int whichError;
MyErrorBox({super.key, required this.whichError});
@override
State<MyErrorBox> createState() => MyErrorBoxState();
}
class MyErrorBoxState extends State<MyErrorBox> {
late final int et;
List<String> someL = CreateAccountWidget.errorMessages;
@override
//updates the variable et
void initState() {
// TODO: implement initState
super.initState();
et = widget.whichError;
}
@override
Widget build(BuildContext context) {
someL = CreateAccountWidget.errorMessages;
print("IN THE BUILD METHOD:");
print(someL[et]);
print("");
return SizedBox(
width: 280,
height: 55,
child: DecoratedBox(
decoration: const BoxDecoration(color: Color.fromRGBO(255, 0, 0, .7)),
child: Center(
child: Text(
someL[et],
style: const TextStyle(
color: Colors.white,
),
),
),
),
);
}
}
When I run the program and it makes the error boxes, the initial errors are correct. After that, the code only runs the build method for any additional errors added to the errors list, and ignores rebuilding the first part of the list, resulting in the first errors not getting updated.
I expected Flutter to rebuild all the items in the Column list because there was a change of state for those errors, but it did not. I'm not sure if this has been answered before, because all of the other questions I have seen in relation to this issue were because the users were trying to update the code in the initState() method.
Here is the implemented solution:
Here is the output from the implemented code after running the 1st test case of "p" as editor1.text, and nothing in the other 2 textFields, and the 2nd test case of every textField empty:
NEW UPDATE ERROR---------------------------- [The password field cannot be empty, The username must be at least 8 letters]
INSIDE THE INIT
THIS IS AN ERROR BOX: The password field cannot be empty
INSIDE THE INIT
THIS IS AN ERROR BOX: The username must be at least 8 letters
As you can see, the second output does not show the 1st and 2nd error boxes in the list be initalized and they stay the same as before.
NEW UPDATE ERROR---------------------------- [The username field cannot be empty, The password field cannot be empty, The username must be at least 8 letters]
THIS IS AN ERROR BOX: The password field cannot be empty
THIS IS AN ERROR BOX: The username must be at least 8 letters
INSIDE THE INIT
THIS IS AN ERROR BOX: The username must be at least 8 letters