Forms and its validation in Flutter

Muhammad Mashood Siddiquie
Analytics Vidhya
Published in
7 min readJun 9, 2020

Hello, everyone, I hope you guys are doing well, Today we’ll be discussing forms in a flutter app, this article includes how to use forms and validation of forms in easy steps:

Step 1: Firstly create a brand new project of flutter and carry on with me how to create forms and validate them.

Step 2: Now create project structure like I am having, which is described below in the image:

Step 3: Now Create a new file inside the Screens folder having name form_screen.dart and copy-paste the following code inside it

import 'package:flutter/material.dart';


class FormScreen extends StatefulWidget {
@override
_FormScreenState createState() => _FormScreenState();
}

class _FormScreenState extends State<FormScreen> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Home'),
actions: [
IconButton(icon: Icon(Icons.add),
onPressed: (){},
splashColor: Colors.deepOrange,
),
],
),
);
}
}

Step 4: Now remove all code from main.dart and copy-paste the following code inside main.dart:

import 'package:flutter/material.dart';
import './screens/form_screen.dart';
void main()=>runApp(
Settings());


class Settings extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
primaryColor: Colors.deepPurpleAccent,
accentColor: Colors.amber,

),
home: FormScreen(),
);
}
}

Step 5: let's move on to form_screen and create a form inside it.

a) First, create a global key of form state which will look after the form either its current state is validated or not what’s the status of the form.

final _formkey = GlobalKey<FormState>();

b) Now create a form inside form_screen:

import 'package:flutter/material.dart';

class FormScreen extends StatefulWidget {
@override
_FormScreenState createState() => _FormScreenState();
}

class _FormScreenState extends State<FormScreen> {
final _formkey = GlobalKey<FormState>();

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Home'),
actions: [
IconButton(
icon: Icon(Icons.add),
onPressed: () {},
splashColor: Colors.deepOrange,
),
],
),
body: Form(
key: _formkey,
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [],
),
),
),
);
}
}

when we pass _formkey to the parameter key of Form that means this key will hold all the states of the form either all fields are entered i.e is form validated or not and much more. If we are using Column inside form it’ll be great to have a single child scroll view as a parent of Column for screen size issues well you can manage this according to your need with MediaQuery but as I am covering forms so I won’t be focusing on MediaQuery.

Step 6: Now Create a file inside the widget folder with name app_text_form_field.dart and copy-paste the following code:

import 'package:flutter/material.dart';

class AppTextFormField extends StatelessWidget {
final titleLabel;
final maxLength;
final icon;
final controller;
final inputType;
final Function fieldSubmit;
final focusnode;
final validator;
final inputAction;

AppTextFormField(
{@required this.titleLabel,
@required this.maxLength,
@required this.icon,
@required this.validator,
@required this.controller,
@required this.inputAction,
this.focusnode,
this.fieldSubmit,
@required this.inputType});

@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(10.0),
child: TextFormField(
maxLength: maxLength,
controller: controller,
keyboardType: inputType,
validator: validator,
textInputAction: inputAction,
onFieldSubmitted: fieldSubmit,
focusNode: focusnode,
decoration: InputDecoration(
labelText: titleLabel,
suffixIcon: Icon(
icon,
color: Colors.black,
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: BorderSide(color: Colors.black),
),
),
),
);
}
}

In this file, we create a text form field some important points which I am telling you are on field submitted, focus node, validator, text input action, keyboard type.

  1. onFieldSubmitted: This is called when we press the enter button of the keyboard of a mobile, this method is triggered and executes the code inside of it.
  2. Focus node: Focus node is simply the focus of each text field.
  3. validator: In this validator, it takes a function having parameter value or whatever name you like which checks if the value is empty then return a String value or return null when the value is not null. for eg:

validator: (value) {
if (value.isEmpty) {
return ‘Please provide a value.’;
}
return null;
},

4. text input action: text input actions describe when you press the enter of the keyboard what type of action do you want to perform either you want to go to the next field or you have done with all the fields and much more.

5. keyboard type: It defines what type of input do you want either you want text input type or number input type or email etc.

6. You can see in the constructor of AppTextFormField I have two properties that are not required it’s because at the end of form we don't want to call the next field according to my scenario we can use it if we want to do any operation like maybe save or doing something else. In the end, we want to be done with form that's why we don't put it as required similarly at first form field we don't want a focus node because we want to go to another text form field so our first form field doesn’t require any focus node.

Step 7: Now Lets back to our form_screen and import app_text_form_field in form_screen.dart:

import '../widgets/app_text_form_field.dart';

Step 8: Create 6 properties 3 of focus node and 3 of text editing controller inside form_screen.dart:

final nameFocusNode = FocusNode();
final emailFocusNode = FocusNode();
final PhoneNoFocusNode = FocusNode();

final nameController = TextEditingController();
final emailController = TextEditingController();
final phoneNoController = TextEditingController();

Step 9: Create 3 AppTextFormField inside the column of form widget or copy-paste this code:

AppTextFormField(
titleLabel: 'Enter Your Name',
inputAction: TextInputAction.next,
validator: (value) {
if (value.isEmpty) {
return 'Please Enter name.';
}
return null;
},
inputType: TextInputType.text,
icon: Icons.person_pin,
maxLength: 20,
fieldSubmit: (_) {
FocusScope.of(context).requestFocus(emailFocusNode);
},
controller: nameController,
),
AppTextFormField(
titleLabel: 'Enter Your Email',
inputAction: TextInputAction.next,
validator: (value) {
if (value.isEmpty) {
return 'Please Enter Email.';
}
return null;
},
inputType: TextInputType.emailAddress,
icon: Icons.email,
maxLength: 20,
focusnode: emailFocusNode,
fieldSubmit: (_) {
FocusScope.of(context).requestFocus(PhoneNoFocusNode);
},
controller: emailController,
),
AppTextFormField(
titleLabel: 'Enter Your Phone Number',
inputAction: TextInputAction.done,
validator: (value) {
if (value.isEmpty) {
return 'Please Enter Phone Number.';
}
return null;
},
inputType: TextInputType.number,
icon: Icons.phone_android,
maxLength: 20,
focusnode: PhoneNoFocusNode,

controller: phoneNoController,
),

now each AppTextFormField has a title, which is a string, an input action which can be next or done, a validator to check if the value is provided or not, an input type which describes what type of input we want, an icon on a text field, max length of a text field that how many characters do we want to insert in a text field, a controller which controls the data of the text form fields and the important point focus node which tells that on every field submit method we are requesting a focus on that text field i.e in first form field we have submitted field method which is requesting focus of the email text form field, that’s why we used text input action to go to another text field and if not found then we pass done as text input action.

Step 10: Create a raised button inside the Column of form widget:

RaisedButton(
focusColor: Theme.of(context).primaryColor,
child: Text(
'Submit',
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.w700,
fontSize: 18
),
),
color: Theme.of(context).accentColor,
splashColor: Colors.deepOrangeAccent,
onPressed: () {},
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15),
),
)

Now let’s work inside the on pressed method:

onPressed: () {
if (_formkey.currentState.validate()) {
_showErrorDialog(context, 'Form Submitted', 'Success');
nameController.clear();
phoneNoController.clear();
emailController.clear();
} else {
_showErrorDialog(context, 'Form Failed', 'Failed');
}
},

here we are checking if the form is validated that means if all values are not null then show a dialog of success and if any of the fields is empty then it will show a dialog with failure and also highlight that field too.

Step 10: Its the most important step as we want to dispose of all the text editing controller and focus node so if we destroy the screen then it’ll not take the memory and free up space it took before, call the dispose method inside _formScreenState class and copy-paste the following code:

@override
void dispose() {
super.dispose();
emailController.dispose();
nameController.dispose();
phoneNoController.dispose();
PhoneNoFocusNode.dispose();
emailFocusNode.dispose();

}

That’s all now let’s run the app and see the magic of flutter forms ❤

  1. Let’s check out if we don’t enter any value in name text form field and press the submit button you’ll have this output:

As you can see it pop up the dialog with failure and at back you can see it highlights the field also.

2. Now Let’s enter all field data and press the submit button, that'll be the output:

As you can see a pop up of success appears and also all the fields at back gets empty too.

That's the power of flutter, little bit coding with maximum output ❤ .

I hope this article makes you clear about using forms in flutter and how to validate them too.

Leave a clap if you find it out useful for you and also follow me on medium.

Github repo link:

Don’t forget to give a star and follow me there for a useful repository for a flutter.

--

--