skip to Main Content

"I’ve just started with Flutter and I’m trying to create a simple login application. Everything seems correct, but it looks like the navigation to the other page isn’t working.I noticed that in this part of the code, the username and password variables are empty, which is why the navigation is not happening.But I cant figure out why these vaiable are empty

if(_formKey.currentState!.validate()) {
  _formKey.currentState!.save();
  print("User: "+Username);
  print("Password"+Password);
  if(Username=="a" && Password=="a" ){
  Get.to(Content());

  }

This is complete code

  late TextEditingController emailController;
  late TextEditingController passwordController;
  String Username="";
  String Password="";
  final _formKey = GlobalKey<FormState>();
  @override
  void initState() {
    super.initState();
    emailController=TextEditingController();
    passwordController=TextEditingController();
  }
  @override
  void dispose() {
    // TODO: implement dispose
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Center(child: Text('Login-Register')),
      ),
      body: SafeArea(
        child: Padding(
          padding: const EdgeInsets.all(40.0),
          child: Form(
            key: _formKey,
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              crossAxisAlignment: CrossAxisAlignment.center,
              children: [
                buildTextFormField(Icons.person, "Username", false,Username),
                SizedBox(height: 15),
                buildTextFormField(Icons.lock, "Password", true,Password),
                SizedBox(height: 15),
                SizedBox(
                    width: double.infinity,
                    child: ElevatedButton(
                        style: ButtonStyle(

                            backgroundColor:
                                MaterialStatePropertyAll(Colors.green)),
                        child: Text("Sign-In"),
                        onPressed: () {

    if(_formKey.currentState!.validate()) {
      _formKey.currentState!.save();
      print("User: "+Username);
      print("Password"+Password);
      if(Username=="a" && Password=="a" ){
      Get.to(Content());

      }
    }

    })),
                Row(
                  mainAxisAlignment: MainAxisAlignment.spaceAround,
                  children: [
                    TextButton(onPressed: () {}, child: Text("Forgot Password")),
                    TextButton(onPressed: () {}, child: Text("Register")),
                  ],
                )
              ],
            ),
          ),
        ),
      ),
    );
  }

  TextFormField buildTextFormField(
      IconData icon, String hint, bool isPassword,String val) {
    return TextFormField(
initialValue: "a",
      onSaved: (value){
        val=value!;

      },
      obscureText: isPassword,
      decoration: InputDecoration(
        prefixIcon: Icon(icon),
        border: OutlineInputBorder(
          borderRadius: BorderRadius.all(
            Radius.circular(40),
          ),
        ),
        hintText: hint,
      ),
    );

}

2

Answers


  1. The val parameter in the onSaved method of buildTextFormField method is being passed by value, not by reference hence doing val=value! does not update the Username and Password variables in your widget state. You should directly update the Username and Password variables in the onSaved method. Follow the below modifications to your code:

    Modify the buildTextFormField method to take an onSave callback

    TextFormField buildTextFormField(
        IconData icon, String hint, bool isPassword, Function(String?) onSave) {
      return TextFormField(
        onSaved: onSave,
        obscureText: isPassword,
        decoration: InputDecoration(
          prefixIcon: Icon(icon),
          border: OutlineInputBorder(
            borderRadius: BorderRadius.all(
              Radius.circular(40),
            ),
          ),
          hintText: hint,
        ),
      );
    }
    

    Replace the usage for username and password as shown below:

    buildTextFormField(Icons.person, "Username", false, (value) {
      Username = value!;
    }),
    SizedBox(height: 15),
    buildTextFormField(Icons.lock, "Password", true, (value) {
      Password = value!;
    }),
    

    With the above setup, making calls to _formKey.currentState!.save() should correctly update the Username and Password variables, and your navigation logic should work as expected.

    Login or Signup to reply.
  2. Thanks for posting the full class! I took some time to read through all of it; Codefarmer’s answer is 100% on point, but I have a few small pieces of advice I wanted to share:

    Single-line functions

    If a function only has one expression, you can use => instead of {} to make it look a little nicer. These two function calls have the same behavior:

    buildTextFormField(Icons.lock, "Password", true, (value) {
      Password = value!;
    }),
    
    buildTextFormField(Icons.lock, "Password", true, (value) => Password = value!),
    

    Function vs. Class

    Here’s some advice that will make your app run faster: if you want to clean up a build method, the best practice is to create another class instead of making a function. Functions are evaluated any time the widget is rebuilt, but widget classes are only rebuilt when needed.

    Don’t do this:

    TextFormField buildTextFormField(
      IconData icon, String hint, bool isPassword, String val) {
      return TextFormField(...);
    }
    

    Do this instead:

    class _TextFormField extends StatelessWidget {
      const _TextFormField(this.icon, this.hint, this.isPassword, this.onSaved);
      final IconData icon;
      final String hint;
      final bool isPassword;
      final ValueChanged<String?> onSaved;
    
      @override
      Widget build(BuildContext context) {
        return TextFormField(...);
      }
    }
    

    It’s more code to write, but it runs better 🙂

    There were a couple of other small things; I’ll paste my version of the class below so you can take a look:

    class LoginRegister extends StatefulWidget {
      const LoginRegister({super.key});
      @override
      State<LoginRegister> createState() => _LoginRegisterState();
    }
    
    class _LoginRegisterState extends State<LoginRegister> {
      /// you can initialize [emailController] and [passwordController] here;
      /// no need for [initState] or [dispose] unless you add other stuff
      late final emailController = TextEditingController();
      late final passwordController = TextEditingController();
    
      /// In general, Dart classes are capitalized and variables aren't.
      /// (no need to initialize to empty string since they're initialized to 'a' later)
      late String username, password;
      final _formKey = GlobalKey<FormState>();
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(title: const Center(child: Text('Login-Register'))),
          body: SafeArea(
            child: Padding(
              padding: const EdgeInsets.all(40),
              child: Form(
                key: _formKey,
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: [
                    _TextFormField(
                      Icons.person,
                      'Username',
                      onSaved: (value) => username = value!,
                    ),
                    _TextFormField(
                      Icons.lock,
                      'Password',
                      isPassword: true,
                      onSaved: (value) => password = value!,
                    ),
                    SizedBox(
                      width: double.infinity,
                      child: ElevatedButton(
                        // ElevatedButton.styleFrom() is really convenient,
                        // since you don't have to use MaterialStatePropertyAll
                        style: ElevatedButton.styleFrom(backgroundColor: Colors.green),
                        child: const Text('Sign-In'),
                        onPressed: () {
                          if (_formKey.currentState!.validate()) {
                            _formKey.currentState!.save();
    
                            print('Username: $username');
                            print('Password: $password');
                            if (username == 'a' && password == 'a') print('it worked!');
                          }
                        },
                      ),
                    ),
                    Row(
                      mainAxisAlignment: MainAxisAlignment.spaceAround,
                      children: [
                        TextButton(onPressed: () {}, child: const Text('Forgot Password')),
                        TextButton(onPressed: () {}, child: const Text('Register')),
                      ],
                    )
                  ],
                ),
              ),
            ),
          ),
        );
      }
    }
    
    class _TextFormField extends StatelessWidget {
      const _TextFormField(
        this.icon,
        this.hint, {
        this.isPassword = false,
        required this.onSaved,
      });
      final IconData icon;
      final String hint;
      final bool isPassword;
      final ValueChanged<String?> onSaved;
    
      @override
      Widget build(BuildContext context) {
        return Padding(
          padding: const EdgeInsets.only(bottom: 15),
          child: TextFormField(
            initialValue: 'a',
            onSaved: onSaved,
            obscureText: isPassword,
            decoration: InputDecoration(
              prefixIcon: Icon(icon),
              border: const OutlineInputBorder(
                borderRadius: BorderRadius.all(Radius.circular(40)),
              ),
              hintText: hint,
            ),
          ),
        );
      }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search