Tutorials

Snippets

Search

Tags

Subscribe on Youtube

Form Validation in Flutter for Beginners

Cover image

Validating forms is a common practice in all digital interactions, mobile apps are no different. Today we'll be building a very simple form validation to show you how this is done in Flutter.

Flutter provides us with a Form widget. You can build up your child of the widget how you want and just add TextFormField widgets to make it apart of the form. Any TextFormField in the Form child widget will become a field in the Form that you can work with. Each form has to be given a key of type FormState that allows you to access the state at any time.

We'll make a form that takes in a name, a number and an email and we'll validate all of them. We'll start off with a basic project and just add a statefull HomeView under the main app.

class MyApp extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return MaterialApp(
       home: HomeView());
  }
}

class HomeView extends StatefulWidget {
  
  _HomeViewState createState() => _HomeViewState();
}

class _HomeViewState extends State<HomeView> {
  
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container()
    );
  }
}

For the Body of the Scaffold we'll add a Form and in the Form we'll add a empty Column. We'll also provide the Form with a key that we can use to check the state and ask the form to save.

class _HomeViewState extends State<HomeView> {
  final GlobalKey<FormState> _formKey = GlobalKey<FormState>();

  
  Widget build(BuildContext context) {
    return Scaffold(
      body: Form(
        key: _formKey,
        child: Column(children: <Widget>[

        ]),
      )
    );
  }
}

That's all the setup done. Lets add our first Field. We'll start with the name. In the Column add a TextFormField widget, give it a keyboard type of text and a validation function. For validation we'll just check if the name is less than 2 characters and show a validation error if it is. In the validator function when you return a string it will take it as a validation error message. If you return nothing then there will be no error.

...
 Widget build(BuildContext context) {
    return Scaffold(
      body: Form(
        key: _formKey,
        child: Column(children: <Widget>[
          TextFormField(
            decoration: const InputDecoration(labelText: 'Name'),
            keyboardType: TextInputType.text,
            validator: (value) {
              if(value.length < 2){
                return 'Name not long enough';
              }
            },
          ),
        ]),
      )
    );
  }
...

If you type in the field you'll see no validation messages come up. This is because the form does not auto validate. To enable this set the autovalidate value to true for the enclosing Form widget.

Form(
  autovalidate: true,
  key: _formKey,
  child: Column(children: <Widget>[ ... ]),
);

With this enabled you will now get validation ON ALL FIELDS, every time you type a character. Next we'll get and save the form data when the user is ready. Add a FloatingActionButton that checks if the form is valid using the key and then calling save if it is.

...
return Scaffold(
 floatingActionButton: FloatingActionButton(
  onPressed: () {
      if(_formKey.currentState.validate()) {
        _formKey.currentState.save();
      }
    },
  ),
...
);

When this function is called on the currentState it triggers a callback on ALL TextFormFields called onSaved. This function returns the current text in the field. We'll use this to save our data into a variable and then we can use it after the save call. Add the onSaved callback to your TextFormField.

// Add name variable to the class
String _name;

...
 TextFormField(
    decoration: const InputDecoration(labelText: 'Name'),
    ...
    onSaved: (value)  => _name = value,
 );

That's everything you would need to build out a text form. Now we can duplicate and update validation for the other fields. Lets do email next.

 TextFormField(
    decoration: const InputDecoration(labelText: 'Email'),
    keyboardType: TextInputType.emailAddress,
    validator: (value) {
      if (!EmailValidator.validate(value)) {
        return 'Please enter a valid email';
      }
    },
  ),

The validation will be done using the EmailValidator package so add it into your pubspec.

email_validator: ^1.0.0

Then lastly we can add our phone field.

TextFormField(
    decoration: const InputDecoration(labelText: 'Mobile'),
    keyboardType: TextInputType.phone,
    validator: (value) {
      var potentialNumber = int.tryParse(value);
      if (potentialNumber == null) {
        return 'Enter a phone number';
      }
    },
  ),

We'll check if it's a number, if it's not we'll show the message. Make sure to set the keyboardType to phone.

That's it for form validation. All you have to do is set the values for each field on the onSave function like with _name. Checkout all the other snippets here. You might find some more Flutter magic.

Also check out

Cover image

Flutter Basics - Going from setState to Architecture

In this tutorial I will be going over how to handle a common async situation in Flutter, without throwing architectures at the problem

Link
Cover image

A Guide to setting up better Logging in Flutter

This article covers logging in Flutter to help with debugging.

Link
Cover image

Easy toasts with OkToast

This tutorial covers an easy way to show and style toast messages.

Link