Open LordOfTheNeverThere opened 3 years ago
I manage to do it like this: (Can't say if it's the best way)
ReactiveForm(
formGroup: this.authForm,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image.asset(
"Assets/images/HOLI_titleNBG.png",
height: 50,
),
SizedBox(
width: 30,
),
CustomText(
text: "Dashboard",
size: 50,
color: Colors.white,
)
],
),
ReactiveTextField(
formControlName: 'username',
decoration: InputDecoration(
hintText: "Insert your Username", labelText: "Username"),
validationMessages: (control) => {
ValidationMessage.required:
"The Username must not be empty",
},
),
ReactiveTextField(
formControlName: 'password',
obscureText: true,
decoration: InputDecoration(
labelText: 'Password',
hintText: 'Insert your Password!',
),
validationMessages: (control) => {
ValidationMessage.required:
"The password must not be empty",
'incorrect':
'Your Username and password combination are incorrect'
}),
ReactiveFormConsumer(builder: (context, authForm, child) {
return TextButton(
child: CustomText(
text: "Sign In!",
),
onPressed: () {
if (authForm.valid) {
// If the Form is valid (It will be valid if the _isCorrectPassword returns null)
Get.to(Layout());
} else {
// Otherwise it will release the error "incorrect" which will notify the user that their password or username are incorrect
authForm.control('password').setErrors({'incorrect': true});
authForm.control('password').markAsTouched(); // Makes the error visible to the user
}
},
);
}),
],
),
)
// Async Custom Group Validator
AsyncValidatorFunction _isCorrectPassword(
String controlName, String passwordControlName) {
return (AbstractControl<dynamic> control) async {
final form = control as FormGroup;
final username = form.control(controlName);
final password = form.control(passwordControlName);
var incorrect = false;
for (var User in users) {
await Future.delayed(
Duration(milliseconds: 500)); //Simulate server request
if (await Future.delayed( Duration (milliseconds: 500), () => User.username != username.value || User.password != password.value)) {
// If one of these informations prompted by the user is wrong it means the user cannot log in
//Simulate server request, so there is time for the information to be gathered before advancing to a new code line
form.markAllAsTouched();
incorrect = true;
} else if (!incorrect) { //If the password and username combination is right it means the user prompted the right information
return Future.value(null);
}
}
};
}
Nothing Further to add
In my opinion this an issue why I'm not using this package. I wanted that error text show only when I'm checking is form valid, not by touching. And it seems there is no easy way how to bypass it.
You can use ReactiveFormField.showErrors
.
I still can't even with showErrors manage to do something similar to:
if (_formKey.currentState!.validate()) {
FocusScope.of(context).unfocus();
_formKey.currentState!.save();
where on validate it checks or marks form fields as invalid if that's the case
The validation seems are checked every time a change value in form field
Well you have to track your custom state yourself.
bool mySaveButtonWasClicked = false;
...
showErrors: (control) => mySaveButtonWasClicked
Yeah that was only solution I could also came up with. Was hoping that form has parameter inside a class, that checks if form was validated manually with some class function validate().
I had the same problem and managed to solve it this way:
bool _canRequest = false;
MaterialButton(
child: Text("Press me"),
onPressed: () async {
_canRequest = true;
await Future.forEach<AsyncValidatorFunction>(
form.asyncValidators, (validator) => validator(form));
_canRequest = false;
},
)
Future<Map<String, dynamic>?> _validator(AbstractControl control) async {
if (!_canRequest) return null;
final FormGroup form = control as FormGroup;
// Simulate an asynchronous action
final String email = "abc@def.com";
final String password = (["correct", "incorrect"]..shuffle()).first;
await Future.delayed(Duration(seconds: 5));
if (password == "correct") return null;
form.control("password").setErrors({"password": "Invalid password"});
}
No more changes needed!
Hi there! I couldn't see any examples of form validation that occurs only after we have tried to submit a form, such is the case when we wish to check if the user is in our DB and if the inputted password is his.
Is there any way to mark the form touched only after submission?
Example:
P.S: I apologize for any mistakes, I am still a rookie at Flutter.
Thanks! :) Nice work!