Search code examples
flutterflutter-change-notifier

Transferring a dart setter around in flutter


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:

  1. Can I pass around the setter from the user model, like I did below. Or is there a better way.
  2. 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;
}

Solution

  • 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;