I am working on creating a signup process with multiple screens. For now I have first name and age screen. I have the following usermodel. The idea is whenever I update one of the field, it triggers rebuild of the signup-screen, so that the next item in sign-up is shown. I have 2 questions:
- Can I pass around the setter from the user model, like I did below. Or is there a better way.
- I am getting the following error when I click the 'Next_na' button inorder to add the first name
LateInitializationError: Field 'firstName' has not been initialized.
Thank you for your help in advance!
class UserModel extends ChangeNotifier {
late String firstName;
late int userAge;
int indexer = 0;
set addFName(String firstName) {
firstName = this.firstName;
indexer = indexer 1;
notifyListeners();
}
String get fName {
return firstName;
}
set addUAge(int userAge) {
userAge = this.userAge;
indexer = indexer 1;
notifyListeners();
}
int get uAge {
return userAge;
}
}
The signup screen is as follows
@override
Widget build(BuildContext context) {
return Scaffold(
body: ChangeNotifierProvider(
create: (context) => UserModel(),
child: Center(
child: Padding(
padding: const EdgeInsets.all(18.0),
child: Consumer<UserModel>(builder: (context, user, child) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text(
"Sign Up",
style: TextStyle(fontSize: 24),
textAlign: TextAlign.center,
),
const Divider(
height: 30,
endIndent: 20,
indent: 20,
thickness: 1.5,
color: Colors.grey,
),
const SizedBox(
height: 30,
),
if (user.indexer == 0)
FirstNameWidget(
user: user,
)
else
FirstNameWidget(
user: user,
)
],
);
}),
)),
));
}
and the 'firstNameWidget' that shows the first name field and the 'next' button is as follows:
class FirstNameWidget extends StatelessWidget {
FirstNameWidget({Key? key, required this.user}) : super(key: key);
final UserModel user;
final firstNameController = TextEditingController();
@override
Widget build(BuildContext context) {
return Form(
//key: _firstNameFormKey,
child: Column(
children: [
TextFormField(
keyboardType: TextInputType.text,
controller: firstNameController,
decoration: const InputDecoration(
border: OutlineInputBorder(),
hintText: 'Enter First Name',
),
//autovalidateMode: AutovalidateMode.onUserInteraction,
),
const SizedBox(
height: 20,
),
SizedBox(
width: MediaQuery.of(context).size.width * 0.8,
child: ElevatedButton(
onPressed: () {
print(firstNameController.text);
commitFirstName(fName: firstNameController.text, user: user);
//user.addFName = firstNameController.text;
},
child: const Text('Next_na'),
),
),
],
),
);
}
}
void commitFirstName({required String fName, required UserModel user}) {
user.addFName = fName;
}
CodePudding user response:
You did a mistake in your setter:
firstName = this.firstName;
You assign the class member (which has not been initialized yet) to your firstName param which comes from the TextEditingController.
If you turn this around it should work:
this.firstName = firstName;