In our real-life application, we need async validation for the situation like validating unique username already taken or not or something like that but currently, Flutter does not support async validation out of the box. We can do async validation in a tricky way. If you want to learn how to do async validation in Flutter without any third-party package then this step by step tutorial will help you to make an async validator for your Flutter form.
Scenario: Suppose we have a TextFormField
in our application where the user will put a username. After typing the username when the user focuses out from the input field then we'll check the typed username is available or not via our local database or API service. Let's do that.
Define the variables in your page state class where you want to make async validation.
class HomePageState extends State<HomePage> {
bool _isChecking = false;
dynamic _validationMsg;
final _usernameCtrl = TextEditingController();
...
...
}
Explanation
_isChecking
variable for showing loading symbol at the end of our input box according to async state.
_validationMsg
is for showing validation message.
_usernameCtrl
for controlling/getting value from our input.
Now make an async validation function according to your validation logic. It can be checking the username from your SQLite local database, API service or firebase real-time database. Here I have shown a fake delay for async example.
Future<dynamic> checkUsername(username) async {
_validationMsg = null;
setState(() {});
//do all sync validation
if (username.isEmpty) {
_validationMsg = "username is required";
setState(() {});
return;
}
if (['admin', 'editor', 'user'].contains(username.toLowerCase())) {
_validationMsg = "${username} is reserved username";
setState(() {});
return;
}
// do async validation
_isChecking = true;
setState(() {});
//it's just faking delay, make your won async validation here
await Future.delayed(Duration(seconds: 2));
_isChecking = false;
if (username != 'harun') _validationMsg = "${username} is taken";
setState(() {});
}
Now implement the checkUsername
async validator function on username TextFormField
.
username TextFormField
TextFormField(
decoration: InputDecoration(
hintText: 'username',
suffixIcon: _isChecking ? Transform.scale(scale: 0.5, child: CircularProgressIndicator()) : null,
),
controller: _usernameCtrl,
autovalidateMode: AutovalidateMode.onUserInteraction,
validator: (val) => _validationMsg,
)
Now wrap the TextFormField
with a Focus
widget so that we can detect when our user focuses out from the text field.
Focus(
child: //our TextFormField will be here
onFocusChange: (hasFocus) {
//call the checkUsername()
}
)
After wrapping the Focus
widget.
Focus(
child: TextFormField(
decoration: InputDecoration(
hintText: 'username',
suffixIcon: _isChecking ? Transform.scale(scale: 0.5, child: CircularProgressIndicator()) : null,
),
controller: _usernameCtrl,
autovalidateMode: AutovalidateMode.onUserInteraction,
validator: (val) => _validationMsg,
),
onFocusChange: (hasFocus) {
if (!hasFocus) checkUsername(_usernameCtrl.text);
},
)
Done! our flutter async validator now ready to use. If you find this tutorial post helpful then please share this tutorial with others to learn how to make async validation in Flutter.