Question:
I want the hintText
and border
color of both the username and password fields to turn red when there’s an error. However, only the password field is working correctly, while the username field isn’t reflecting the changes as expected.
Here’s the current behavior I’m seeing:
Code:
I’m using a custom TextFieldWidget
to build the text fields for username and password:
class TextFieldWidget {
static Widget buildTextField({
required TextEditingController controller,
required String fieldTitle,
required String hintText,
bool isPassword = false,
required BuildContext context,
bool obscureText = false,
void Function()? toggleVisibility,
String? errorText,
String? Function(String?)? validator,
}) {
final hasError = errorText != null;
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 10.5),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
fieldTitle,
style: const TextStyle(
color: Colors.black,
),
),
const SizedBox(height: 8.0),
TextFormField(
controller: controller,
obscureText: obscureText,
decoration: InputDecoration(
errorText: hasError ? errorText : null,
errorStyle: const TextStyle(color: Colors.red),
hintText: hintText,
hintStyle: TextStyle(
color: hasError ? Colors.red : Colors.black.withOpacity(0.8),
),
filled: true,
fillColor: hasError ? Colors.red.shade50 : Colors.grey.shade300,
suffixIcon: isPassword
? IconButton(
icon: Icon(
obscureText
? Icons.visibility
: Icons.visibility_off,
color: hasError ? Colors.red : Colors.grey,
),
onPressed: toggleVisibility,
)
: null,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10.0),
borderSide: BorderSide(
color: hasError ? Colors.red : Colors.transparent,
width: 1.5,
),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10.0),
borderSide: BorderSide(
color: hasError ? Colors.red : Colors.grey,
width: 1.5,
),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10.0),
borderSide: BorderSide(
color: hasError ? Colors.red : Colors.black,
width: 1.5,
),
),
errorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10.0),
borderSide: const BorderSide(
color: Colors.red,
width: 1.5,
),
),
focusedErrorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10.0),
borderSide: const BorderSide(
color: Colors.red,
width: 1.5,
),
),
),
validator: validator,
style: TextStyle(
color: hasError ? Colors.red : Colors.black,
),
),
],
),
);
}
}
How I am using the fields:
TextFieldWidget.buildTextField(
controller: _userNameController,
fieldTitle: 'Username',
hintText: 'Enter your username',
context: context,
errorText: _usernameError, // Error text if any
validator: (value) {
if (value == null || value.trim().isEmpty) {
return 'Username is required';
}
return null;
},
),
const SizedBox(height: 15.0),
TextFieldWidget.buildTextField(
controller: _passwordController,
fieldTitle: 'Password',
hintText: 'Enter your password',
isPassword: true,
context: context,
obscureText: obscureText,
toggleVisibility: () {
ref.read(obscureTextProvider.notifier).state = !obscureText;
},
errorText: _passwordError,
),
OnSubmit Function
Future<void> _onSubmit() async {
setState(() {
_usernameError = null;
_passwordError = null;
});
bool isFormValid = _formKey.currentState!.validate();
if (isFormValid) {
final name = _userNameController.text;
final password = _passwordController.text;
try {
await ref.read(authProvider).login(name, password, rememberMe: _rememberMe);
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (_) => const HomeMainScreen()),
);
} catch (e) {
setState(() {
_errorMessage = e.toString();
if (_errorMessage!.contains('username')) {
_usernameError = _errorMessage;
} else if (_errorMessage!.contains('password')) {
_passwordError = _errorMessage;
}
});
}
}
}
Problem:
The password field shows the error as expected, but the username field doesn’t apply the red color to the hintText
and border
when there’s an error. What am I missing? How can I ensure both the username and password fields display the error in the same way?
Variables Used:
String? _errorMessage;
String? _usernameError;
String? _passwordError;
late TextEditingController _userNameController;
late TextEditingController _passwordController;
Expected behavior:
- Both fields should display red
hintText
and red border when there’s an error.
Current behavior:
- Only the password field is working as expected, while the username field does not reflect the red border and
hintText
.
Any guidance would be greatly appreciated!
I think it could be because on the validator param for the username, you are only validating that it should be null or an empty string for it to be an error. I would suggest to first force the error in the validator conditional to see if the color changes. In the screenshot that you are displaying, the username contains a string so it would not be wrong.
If there are still no color showing maybe you could try and add the ‘_usernameError’ variable to the validator as well