Implementing Form Validation in Flutter: A Step-by-Step Guide
Flutter, Google’s UI toolkit for building natively compiled applications, provides a rich set of widgets and tools to create beautiful and functional user interfaces.
As a Flutter developer, I understand the importance of user input validation in creating a seamless and error-free user experience. In this guide, I’ll walk you through the process of implementing form validation in a Flutter application, ensuring that the data entered by users meets the specified criteria.
Navigate to the project directory and Open the project in your preferred IDE, such as Visual Studio Code or Android Studio.
Creating a Form
In Flutter, we use the Form
widget to define a form, containing a collection of TextFormField
widgets. Let's start by creating a simple form:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: MyForm(),
);
}
}
class MyForm extends StatefulWidget {
@override
_MyFormState createState() => _MyFormState();
}
class _MyFormState extends State<MyForm> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Form Validation Example'),
),
body: Padding(
padding: EdgeInsets.all(16.0),
child: Form(
child: Column(
children: [
// Add form fields here
],
),
),
),
);
}
}
Adding Form Fields
Let’s incorporate text fields for the user’s name and email address, along with a button to submit the form:
// Inside the _MyFormState class
TextEditingController _nameController = TextEditingController();
TextEditingController _emailController = TextEditingController();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Form Validation Example'),
),
body: Padding(
padding: EdgeInsets.all(16.0),
child: Form(
child: Column(
children: [
TextFormField(
controller: _nameController,
decoration: InputDecoration(labelText: 'Name'),
validator: (value) {
if (value.isEmpty) {
return 'Please enter your name';
}
return null;
},
),
TextFormField(
controller: _emailController,
decoration: InputDecoration(labelText: 'Email'),
validator: (value) {
if (value.isEmpty || !value.contains('@')) {
return 'Please enter a valid email address';
}
return null;
},
),
SizedBox(height: 16.0),
ElevatedButton(
onPressed: () {
// Validate the form
if (Form.of(context).validate()) {
// Form is valid, submit data
// Add your form submission logic here
}
},
child: Text('Submit'),
),
],
),
),
),
);
}
Form Validation Logic
Validation logic is applied using the validator
property of each TextFormField
. This function checks the entered value and returns an error message if it's invalid or null
if it's valid.
Form validation occurs when the user presses the submit button. The Form.of(context).validate()
function checks all form fields for validation. If any field fails validation, the error message is displayed, and the form is not submitted.
We’ll explore asynchronous validation, custom validation logic, and the use of the FormState
class for more control over the form.
Asynchronous Validation
Sometimes, validation requires asynchronous operations, such as checking if an email address is already in use. Let’s enhance the email validation to include an asynchronous check:
// Inside the _MyFormState class
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Form Validation Example'),
),
body: Padding(
padding: EdgeInsets.all(16.0),
child: Form(
child: Column(
children: [
TextFormField(
controller: _nameController,
decoration: InputDecoration(labelText: 'Name'),
validator: (value) {
if (value.isEmpty) {
return 'Please enter your name';
}
return null;
},
),
TextFormField(
controller: _emailController,
decoration: InputDecoration(labelText: 'Email'),
validator: (value) async {
if (value.isEmpty) {
return 'Please enter an email address';
}
// Simulate an asynchronous check
await Future.delayed(Duration(seconds: 1));
if (!value.contains('@')) {
return 'Please enter a valid email address';
}
return null;
},
),
SizedBox(height: 16.0),
ElevatedButton(
onPressed: () {
// Validate the form
if (Form.of(context).validate()) {
// Form is valid, submit data
// Add your form submission logic here
}
},
child: Text('Submit'),
),
],
),
),
),
);
}
Note the use of the async
keyword in the validator function for the email field. This allows us to use asynchronous operations within the validation logic.
Custom Validation Logic
You might encounter scenarios where built-in validators are not sufficient. For example, let’s create a custom validator to ensure that the entered name contains at least two words:
// Inside the _MyFormState class
String _validateName(String value) {
if (value.isEmpty) {
return 'Please enter your name';
}
List<String> words = value.split(' ');
if (words.length < 2) {
return 'Please enter at least two words';
}
return null;
}
// Inside the build method
TextFormField(
controller: _nameController,
decoration: InputDecoration(labelText: 'Name'),
validator: _validateName,
),
Here, we’ve defined a custom _validateName
function that checks if the entered name has at least two words.
Using FormState for More Control
The FormState
class allows us to interact with the form outside the build method, providing more control. Let's use it to programmatically reset the form:
// Inside the _MyFormState class
final _formKey = GlobalKey<FormState>();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Form Validation Example'),
),
body: Padding(
padding: EdgeInsets.all(16.0),
child: Form(
key: _formKey, // Assign a global key to the form
child: Column(
children: [
TextFormField(
controller: _nameController,
decoration: InputDecoration(labelText: 'Name'),
validator: _validateName,
),
TextFormField(
controller: _emailController,
decoration: InputDecoration(labelText: 'Email'),
validator: (value) async {
if (value.isEmpty) {
return 'Please enter an email address';
}
// Simulate an asynchronous check
await Future.delayed(Duration(seconds: 1));
if (!value.contains('@')) {
return 'Please enter a valid email address';
}
return null;
},
),
SizedBox(height: 16.0),
ElevatedButton(
onPressed: () {
// Validate the form
if (_formKey.currentState.validate()) {
// Form is valid, submit data
// Add your form submission logic here
// Reset the form
_formKey.currentState.reset();
}
},
child: Text('Submit'),
),
],
),
),
),
);
}
In this example, we’ve assigned a global key (_formKey
) to the form. We then use this key with _formKey.currentState
to access the FormState
and call its methods, such as validate()
for validation and reset()
to clear the form.
Conclusion
In conclusion, form validation is a critical aspect of developing user-friendly Flutter applications. By following this guide, you’ll be able to enhance your app’s user interface and ensure a smooth user experience. Flutter’s flexibility and cross-platform capabilities make it a powerful choice for building applications with a consistent codebase. Go code dude.
CONTACT :
— Email → [email protected]
— Github → https://github.com/habbichelotfi
— LinkedIn → www.linkedin.com/in/lotfi-habbiche
SUPPORT ME :
— PayPal → https://paypal.me/lotfihabbiche?country.x=FR&locale.x=fr_FR
— Buy My Apps → https://habbiche.gumroad.com/
— My Portfolio → https://lotfihabbiche-portfolio.web.app/