Empty controllers in simple login form

55 Views Asked by At

In the following code, I'm trying to make a login screen. However, even after I type email and password, I get a popup telling me "Email or password is empty", which is expected inside my if check.

login_page.dart

import 'package:chat_app/auth/auth_service.dart';
import 'package:chat_app/components/custom_button.dart';
import 'package:chat_app/components/custom_textfield.dart';
import 'package:flutter/material.dart';

class LoginPage extends StatelessWidget {
  final void Function()? onTap;

  LoginPage({super.key, required this.onTap});

  final TextEditingController _emailController = TextEditingController();

  final TextEditingController _passwordController = TextEditingController();

  void login(BuildContext context) async {
    final authService = AuthService();
    final localContext = context;

    String email = _emailController.text.trim();
    String password = _passwordController.text.trim();

    if (email.isEmpty || password.isEmpty) {
      showDialog(
        context: localContext,
        builder: (context) => AlertDialog(
          title: const Text("Error"),
          content: const Text("Email or password is empty"),
          actions: [
            TextButton(
              onPressed: () => Navigator.pop(localContext),
              child: const Text("Ok"),
            )
          ],
        ),
      );
      return; // Exit the method if email or password is empty
    }

    try {
      await authService.signInWithEmailAndPassword(
          _emailController.text.trim(), _passwordController.text.trim());
    } catch (e) {
      showDialog(
        context: localContext,
        builder: (localContext) => AlertDialog(
          title: const Text("Error"),
          content: Text(e.toString()),
          actions: [
            TextButton(
              onPressed: () => Navigator.pop(localContext),
              child: const Text("Ok"),
            )
          ],
        ),
      );
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Theme.of(context).colorScheme.background,
      body: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Icon(
            Icons.message_rounded,
            size: 60,
            color: Theme.of(context).colorScheme.primary,
          ),
          const SizedBox(height: 60),
          Text(
            "Welcome back, you've been missed",
            style: TextStyle(
              color: Theme.of(context).colorScheme.primary,
              fontSize: 16,
            ),
          ),
          const SizedBox(height: 20),
          CustomTextField(
            hintText: "[email protected]",
            obscureText: false,
            controller: _emailController,
          ),
          const SizedBox(height: 25),
          CustomTextField(
            hintText: "Password",
            obscureText: true,
            controller: _passwordController,
          ),
          const SizedBox(height: 25),
          CustomButton(text: "Login", onTap: () => login(context)),
          const SizedBox(height: 25),
          Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Text(
                "Not a member? ",
                style: TextStyle(color: Theme.of(context).colorScheme.primary),
              ),
              GestureDetector(
                onTap: onTap,
                child: Text(
                  "Register now",
                  style: TextStyle(
                    fontWeight: FontWeight.bold,
                    color: Theme.of(context).colorScheme.primary,
                  ),
                ),
              )
            ],
          )
        ],
      ),
    );
  }
}

custom_textfield.dart

import 'package:flutter/material.dart';

class CustomTextField extends StatelessWidget {
  final String hintText;
  final bool obscureText;
  final TextEditingController controller = TextEditingController();

  CustomTextField({super.key, required controller, required this.hintText, required this.obscureText});

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.symmetric(horizontal: 25.0),
      child: TextField(
        obscureText: obscureText,
        controller: controller,
        decoration: InputDecoration(
          enabledBorder: OutlineInputBorder(
            borderSide: BorderSide(
              color: Theme.of(context).colorScheme.tertiary,
            ),
            borderRadius: BorderRadius.circular(10),
          ),
          focusedBorder: OutlineInputBorder(
            borderSide: BorderSide(
              color: Theme.of(context).colorScheme.primary,
            ),
            borderRadius: BorderRadius.circular(10),
          ),
          fillColor: Theme.of(context).colorScheme.secondary,
          filled: true,
          hintText: hintText,
          hintStyle: TextStyle(
            color: Theme.of(context).colorScheme.primary,
          ),
        ),
      ),
    );
  }
}

I just can't understand how the controllers are appearing as an empty string like "", as if they aren't receiving values at all. Any sugestions?

2

There are 2 best solutions below

1
Dhafin Rayhan On BEST ANSWER

In CustomTextField, you have a controller field that is initialized with a TextEditingController(), while the controller parameter from the constructor is not used. It makes CustomTextField uses its own TextEditingController instead of using the one passed from the parent widget. Fix it by applying these two changes:

class CustomTextField extends StatelessWidget {
  final String hintText;
  final bool obscureText;
  final TextEditingController controller; // (1) Remove the assignment

  // (2) Change `required controller` to `required this.controller`
  CustomTextField({super.key, required this.controller, required this.hintText, required this.obscureText});
1
Hammad Ali On

Just change the onTap Instead of this

GestureDetector(
                onTap: onTap,
                child: Text(
                  "Register now",
                  style: TextStyle(
                    fontWeight: FontWeight.bold,
                    color: Theme.of(context).colorScheme.primary,
                  ),
                ),
              )

To This

GestureDetector(
                    onTap: ()=>onTap(),
                    child: Text(
                      "Register now",
                      style: TextStyle(
                        fontWeight: FontWeight.bold,
                        color: Theme.of(context).colorScheme.primary,
                      ),
                    ),
                  )