I have a Sign In form validator that is not working as expected. When I leave the email
or password
fields empty or enter something that is not accepted based on what I set on the validator
the error is shown but I'm directed to login success page when I click the login button, which should not be the case. I want to stay on the sign in page until I enter the correct values.
Sign In form
class SignForm extends StatefulWidget {
@override
_SignFormState createState() => _SignFormState();
}
class _SignFormState extends State<SignForm> {
// GlobalKey This uniquely identifies the Form , and allows validation of the form in a later step.
final _formKey = GlobalKey<FormState>();
String email, password;
bool remember = false;
final List<String> errors = [];
// func with named parameter
void addError({String error}) {
if (!errors.contains(error))
setState(() {
errors.add(error);
});
}
void removeError({String error}) {
if (errors.contains(error))
setState(() {
errors.remove(error);
});
}
@override
Widget build(BuildContext context) {
return Form(
key: _formKey,
child: Column(
children: [
// TextFormField - Creates a [FormField] that contains a [TextField].
buildEmailFormField(),
SizedBox(height: getProportionateScreenHeight(30)),
buildPasswordFormField(),
SizedBox(height: getProportionateScreenHeight(30)),
Row(
children: [
Checkbox(
value: remember,
activeColor: kPrimaryColor,
onChanged: (value) {
setState(() {
remember = value;
});
},
),
Text("Remember me"),
Spacer(),
GestureDetector(
onTap: () => Navigator.pushNamed(
context, ForgotPasswordScreen.routeName),
child: Text(
"Forgot Password?",
style: TextStyle(decoration: TextDecoration.underline),
),
)
],
),
FormError(errors: errors),
SizedBox(height: getProportionateScreenHeight(20)),
DefaultButton( < -- WHERE I THINK THE ERROR IS
text: 'Login',
press: () {
if (_formKey.currentState.validate()) {
_formKey.currentState.save(); < -- WHERE I THINK THE ERROR IS
// if all are valid then go to success screen
Navigator.pushReplacementNamed(
context, LoginSuccessScreen.routeName);
}
},
)
],
),
);
}
TextFormField buildPasswordFormField() {
return TextFormField(
// obscure visibility of the password
obscureText: true,
onSaved: (newValue) => password = newValue,
onChanged: (value) {
if (value.isNotEmpty && errors.contains(kPassNullError)) {
removeError(error: kPassNullError);
} else if (value.length >= 8) {
removeError(error: kShortPassError);
}
// In case a user removed some characters below the threshold, show alert
else if (value.length < 8 && value.isNotEmpty) {
addError(error: kShortPassError);
}
return null;
},
validator: (value) {
if (value.isEmpty) {
addError(error: kPassNullError);
removeError(error: kShortPassError);
} else if (value.length < 8 && value.isNotEmpty) {
addError(error: kShortPassError);
}
return null;
},
decoration: InputDecoration(
// uses the InputDecorationTheme defined in my theme.dart file
labelText: "Password",
hintText: "Enter your password",
// When [FloatingLabelBehavior.always] the label will always float at the top of the field above the content.
floatingLabelBehavior: FloatingLabelBehavior.always,
suffixIcon: CustomSuffixIcon(
svgIcon: "assets/icons/Lock.svg",
),
),
);
}
TextFormField buildEmailFormField() {
return TextFormField(
// Requests a keyboard with ready access to the "@" and "." keys.
keyboardType: TextInputType.emailAddress,
onSaved: (newValue) => email = newValue,
onChanged: (value) {
if (value.isNotEmpty && errors.contains(kEmailNullError)) {
removeError(error: kEmailNullError);
} else if (emailValidatorRegExp.hasMatch(value)) {
removeError(error: kInvalidEmailError);
} else if (value.isNotEmpty && !emailValidatorRegExp.hasMatch(value)) {
addError(error: kInvalidEmailError);
return null;
}
},
validator: (value) {
if (value.isEmpty) {
addError(error: kEmailNullError);
removeError(error: kInvalidEmailError);
} else if (value.isNotEmpty && !emailValidatorRegExp.hasMatch(value)) {
addError(error: kInvalidEmailError);
}
return null;
},
decoration: InputDecoration(
// uses the InputDecorationTheme defined in my theme.dart file
labelText: "Email",
hintText: "Enter your email",
// When [FloatingLabelBehavior.always] the label will always float at the top of the field above the content.
floatingLabelBehavior: FloatingLabelBehavior.always,
suffixIcon: CustomSuffixIcon(
svgIcon: "assets/icons/Mail.svg",
),
),
);
}
}
Changing from
final GlobalKey _formKey = GlobalKey<FormState>();
tofinal _formKey = GlobalKey<FormState>();
solved my problem.