avatarLotfi Habbiche

Summarize

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/

If you enjoyed this article, consider trying out the AI service I recommend. It provides the same performance and functions to ChatGPT Plus(GPT-4) but more cost-effective, at just $6/month (Special offer for $1/month). Click here to try ZAI.chat.

Flutter
Form Validation
Forms
Mobile App Development
Flutter App Development
Recommended from ReadMedium