Input validation — flutter.

Michael Adeyemo
7 min readSep 29, 2019

This is a simple flutter app that demonstrate how to validate user input and also handle focus node for the input fields for better user experience.

OVERVIEW OF THE APP

The app will have three text field to collect the username, email and password ,if the input are invalid as determined by our preset rules, we would simply display Invalid username, Invalid email address and Invalid password respectively as shown below.

If you just want to see the code, you can skip to the last section of the article.

Let’s get started

Photo by Serghei Trofimov on Unsplash

Create a new flutter app and clear out the generated code in the main.dart file. Define the main function like this

    void main() => runApp(MyApp());

MyApp will be a StatelessWidget that returns a MaterialApp.

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Input Validation',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: HomePage(),
);
}
}

use the “stful” shortcut to create a StatefullWidget for the HomePage, which would look like this .

class HomePage extends StatefulWidget {
@override
_HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
@override
Widget build(BuildContext context) {
return Container();
}
}

we would return a Scaffold instead of a Container like this.

return Scaffold(
appBar: AppBar(title: Text("Input Validation"),),
body: HomePageBody(),
);

The HomePageBody would be a function that returns a Widget since the Scaffold body property expects a widget. We would come back to this in a moment.

Define private variables in the _HomePageState class that would hold the username, email and password as follows

String _username,_email,_password= "";

Now create the HomePageBody function that returns a Widget like this.

Widget HomePageBody() {
return Container(
padding: const EdgeInsets.all(16),
child: Form(
child: Column(
children: <Widget>[

],
),
),
);
}

Notice that we added a Form Widget to the widget hierarchy, this would come handle when we want to start validating our users input.

Add the following as children to the Column, in a moment, we would start creating them one after each other.

NameInput(),
SizedBox(height: 16,),
EmailInput(),
SizedBox(height: 16,),
PasswordInput(),
SizedBox(height: 16,),
SubmitButton()

Starting with the NameInput widget.

Widget NameInput() {
return TextFormField(
textCapitalization: TextCapitalization.words,
keyboardType: TextInputType.text ,
decoration: InputDecoration(
labelText: "Username",
hintText: "e.g Morgan",
),
textInputAction: TextInputAction.next,
);
}

Notice that we choose to return a TextFormField instead of a TextField, this is done deliberately in order to make the validation simple as you would see soon. The TextFormField has a lot of properties you can explore, The once we care about is the validator and onSaved which we are going to be using in a moment for our validation.

Next to the EmailInput widget.

Widget EmailInput() {
return TextFormField(
keyboardType: TextInputType.emailAddress ,
decoration: InputDecoration(
labelText: "Email",
hintText: "e.g abc@gmail.com",
),
textInputAction: TextInputAction.next,
);
}

Next to the PasswordInput widget.

Widget PasswordInput() {
return TextFormField(
keyboardType: TextInputType.text ,
obscureText: true,
decoration: InputDecoration(
labelText: "Password",
suffixIcon: Icon(Icons.lock),
),
textInputAction: TextInputAction.done,
);
}

Finally the SubmitButton widget.

RaisedButton SubmitButton(){
return RaisedButton(
color:Theme.of(context).primaryColor,
onPressed: (){},
child: Text("Submit",style: TextStyle(color: Colors.white),),
);
}

At this point we have successfully built the UI, but no validation would occur when the user press the submit button.

Validating the Inputs

In order to validate the inputs would need to set the validator property on each textFormField that would return an error message String when the input is not valid and returns null when the input is valid. Here is where we need our Form widget in action because;

The Form widget acts as a container for grouping and validating multiple form fields.

In order to use the form in the validation, we would to create a GlobalKey that would uniquely identify the form. In the _HomePageState class add the GlobalKey that identify the form like this.

final _formKey = GlobalKey<FormState>();

add the key to the form in the HomePageBody.

child: Form(
key: _formKey,
child: ...

Read more on how to do form validation in flutter from here.

Username Validation

In order to validate the username, we need a set of rules to determine what input is valid or not, we would do that using what is called a Regular expression(Regex). I found a good Regex that would service our purpose here.

add the validator and onSaved properties to the NameInput widget like this.

...,
validator: (name){
Pattern pattern =
r'^[A-Za-z0-9]+(?:[ _-][A-Za-z0-9]+)*$';
RegExp regex = new RegExp(pattern);
if (!regex.hasMatch(name))
return 'Invalid username';
else
return null;

},
onSaved: (name)=> _username = name,

email Validation

For the email validation, we would use this special package for the email validation purpose. In the pubspec.yaml file add the package under the dependencies:

email_validator: ^1.0.0

click on the “Packages get” flutter command on the top section.

in the EmailInput widget add these properties.

...,
validator: (email)=>EmailValidator.validate(email)? null:"Invalid email address",
onSaved: (email)=> _email = email,

make sure to import

import 'package:email_validator/email_validator.dart';

password Validation

We would also use a Regular expression to validate the password.

we need a Password that must contain at least one letter, at least one number, and be longer than six charaters. We would get this regular expression from here.

...,
validator: (password){
Pattern pattern =
r'^(?=.*[0-9]+.*)(?=.*[a-zA-Z]+.*)[0-9a-zA-Z]{6,}$';
RegExp regex = new RegExp(pattern);
if (!regex.hasMatch(password))
return 'Invalid password';
else
return null;
},
onSaved: (password)=> _password = password,

We have successfully added the code to validate our users inputs. But its not complete yet. We need to decide when the validation have to occur. In our case, it is when the user decides to submit the form. Therefore in our SubmitButton, we would call the code to do the real validation like this.

In the onPressed property, add this code.

onPressed: (){
if(_formKey.currentState.validate()){
_formKey.currentState.save();
}
},

Now we have successfully validated and saved our _username, _email and _password properties but we are not doing anything with it. In real like applications, you may want to proceed and register the user in your database,but in this app we would just toast the information.

In other to toast the information we need to add the fluttertoast package.

fluttertoast: ^3.1.3

click on the “Packages get” flutter command on the top section.

remember to import the package

import 'package:fluttertoast/fluttertoast.dart';

then create an helper function that would handle the toasting of a message like this.

void toastMessage(String message){
Fluttertoast.showToast(
msg: message,
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.TOP,
timeInSecForIos: 1,
fontSize: 16.0
);
}

Now, call the toastMessage in the onPressed callback of the SubmitButton.

onPressed: (){
if(_formKey.currentState.validate()){
_formKey.currentState.save();
toastMessage("Username: $_username\nEmail: $_email\nPassword: $_password");
}
},

Congratulations!!!. You have successfully validated your user input and saved it for further usage. However in order to improve the user experience we may decide to manage the focus node of the textfields that gives the user a smooth flow of filling the form.

Managing Focus node

FocusNodes are persistent objects that form a focus tree that is a representation of the widgets in the hierarchy that are interested in focus

Managing focus is a fundamental tool for creating forms with an intuitive flow. For example, say you have a search screen with a text field. When the user navigates to the search screen, you can set the focus to the text field for the search term. This allows the user to start typing as soon as the screen is visible, without needing to manually tap the text field.

With these said, now you should know that the benefit of managing the focus node for the user can not be over emphasized.

To get started with managing focus node read this.

In the _HomePageState class, just below the _formKey declaration, add the following code.

FocusNode _usernameFocusNode = FocusNode();
FocusNode _emailFocusNode = FocusNode();
FocusNode _passwordFocusNode = FocusNode();

now create a helper function that would help in changing the focus node.

void fieldFocusChange(BuildContext context, FocusNode currentFocus,FocusNode nextFocus) {
currentFocus.unfocus();
FocusScope.of(context).requestFocus(nextFocus);
}

To the NameInput widget add the following properities.

focusNode: _usernameFocusNode,
autofocus: true,
onFieldSubmitted: (_){
fieldFocusChange(context, _usernameFocusNode, _emailFocusNode);
},

The autofocus property gives the focus to the username textfield as soon as it is visible. The onFieldSubmitted property indicate that we are done typing and want to move to the next focus.

To the EmailInput widget add the following properities.

focusNode: _emailFocusNode,
onFieldSubmitted: (_){
fieldFocusChange(context, _emailFocusNode, _passwordFocusNode);
},

To the PasswordInput widget add the following property.

focusNode: _passwordFocusNode,

Complete code

Congratulation

Photo by Wil Stewart on Unsplash

Congrats, you are finally learnt how to validate user input and also learnt how to improve user experience by managing focus node for your textfields.

Do you need a senior flutter developer? message me..

--

--