close

Textfield validation in Flutter

This is a basic ripple application that show how to approve client input and furthermore handle center hub for the information fields for better client experience.

OVERVIEW OF THE APP

Image for post

The application will have three content field to gather the username, email and secret key ,if the info are invalid as dictated by our preset principles, we would basically show Invalid username, Invalid email address and Invalid secret key individually as demonstrated as follows.

Image for post

In the event that you simply need to see the code, you can jump to the last segment of the article.

Let’s get started

Image for post
Photo by Serghei Trofimov on Unsplash

Make another vacillate application and get out the produced code in the main.dart record. Characterize the primary capacity 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(),
    );
  }
}

utilize the “stful” easy route to make a StatefullWidget for the HomePage, which would resemble this .

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

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

we would restore a Scaffold rather than a Container like this.

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

The HomePageBody would be a capacity that profits a Widget since the Scaffold body property anticipates a gadget. We would return to this in a second.

Characterize private factors in the _HomePageState class that would hold the username, email and secret phrase as follows

String _username,_email,_password= "";

Presently make the HomePageBody work that profits 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 gadget chain of command, this would come handle when we need to begin approving our clients input.

Add the accompanying as kids to the Column, in a second, we would begin making them one after one another.

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

Beginning with the NameInput gadget.

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

Notice that we decide to restore a TextFormField rather than a TextField, this is done purposely to make the approval straightforward as you would see soon. The TextFormField has a great deal of properties you can investigate, The once we care about is the validator and onSaved which we will be utilizing in a second for our approval.

Close to the EmailInput gadget.

Widget EmailInput() {
  return TextFormField(
    keyboardType: TextInputType.emailAddress ,
    decoration: InputDecoration(
      labelText: "Email",
      hintText: "e.g [email protected]",
    ),
    textInputAction: TextInputAction.next,
  );
}

Close to the PasswordInput gadget.

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

At long last the SubmitButton gadget.

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

Now we have effectively assembled the UI, yet no approval would happen when the client press the submit button.

Approving the Inputs

To approve the data sources would have to set the validator property on each textFormField that would restore a blunder message String when the information isn’t legitimate and returns invalid when the information is substantial. Here is the place where we need our Form gadget in real life on the grounds that;

The Form gadget goes about as a holder for gathering and approving numerous structure fields.

To utilize the structure in the approval, we would to make a GlobalKey that would particularly recognize the structure. In the _HomePageState class add the GlobalKey that recognize the structure this way.

final _formKey = GlobalKey<FormState>();

add the way in to the structure in the HomePageBody.

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

Peruse more on the most proficient method to do frame approval in shudder from here.

Username Validation

To approve the username, we need a bunch of rules to figure out what info is substantial or not, we would do that utilizing what is known as a Regular expression(Regex). I found a decent Regex that would support our motivation here.

add the validator and onSaved properties to the NameInput gadget 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 approval, we would utilize this uncommon bundle for the email approval reason. In the pubspec.yaml document add the bundle under the conditions:

email_validator: ^1.0.0

click on the “Bundles get” shudder order on the top area.

in the EmailInput gadget 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';

secret key Validation

We would likewise utilize a Regular articulation to approve the secret phrase.

we need a Password that should contain at any rate one letter, at any rate one number, and be longer than six charaters. We would get this normal articulation 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 effectively added the code to approve our clients inputs. In any case, its not complete yet. We need to choose when the approval need to happen. For our situation, it is the point at which the client chooses to present the structure. Consequently in our SubmitButton, we would call the code to do the genuine approval like this.

In the onPressed property, add this code.

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

Presently we have effectively approved and saved our _username, _email and _password properties however we are not doing anything with it. In genuine like applications, you might need to continue and enroll the client in your database,but in this application we would simply toast the data.

In other to toast the data we need to add the fluttertoast bundle.

fluttertoast: ^3.1.3

click on the “Bundles get” vacillate order on the top area.

make sure to import the bundle

import 'package:fluttertoast/fluttertoast.dart';

at that point make a partner work that would deal with the toasting of a message this way.

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

Presently, 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 effectively approved your client input and saved it for additional use. Anyway to improve the client experience we may choose to deal with the center hub of the textfields that gives the client a smooth progression of filling the structure.

Overseeing Focus hub

FocusNodes are relentless articles that structure a center tree that is a portrayal of the gadgets in the order that are keen on core interest

Overseeing center is a key device for making structures with an instinctive stream. For instance, say you have a hunt screen with a book field. At the point when the client explores to the pursuit screen, you can set the concentration to the content field for the hunt term. This permits the client to begin composing when the screen is noticeable, without expecting to physically tap the content field.

With these stated, presently you should realize that the advantage of dealing with the center hub for the client can not be over underscored.

To begin with overseeing center hub read this.

In the _HomePageState class, just underneath the _formKey statement, add the accompanying code

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

presently make an aide work that would help in changing the center hub.

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

To the NameInput gadget add the accompanying properities.

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

The self-adjust property gives the concentration to the username textfield when it is noticeable. The onFieldSubmitted property show that we are finished composing and need to move to the following core interest.

To the EmailInput gadget add the accompanying properities.

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

To the PasswordInput gadget add the accompanying property.

focusNode: _passwordFocusNode,

Complete code

import 'package:email_validator/email_validator.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:fluttertoast/fluttertoast.dart';

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



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

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

class _HomePageState extends State<HomePage> {


  String _username,_email,_password= "";
  final _formKey = GlobalKey<FormState>();

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



  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("Input Validation"),),
      body: HomePageBody(),
    );
  }

  Widget HomePageBody() {

    return Container(
      padding: EdgeInsets.all(16),
      child: Form(
        key: _formKey,
        child: SingleChildScrollView(
          child: Column(
            children: <Widget>[
              NameInput(),
              SizedBox(height: 16,),
              EmailInput(),
              SizedBox(height: 16,),
              PasswordInput(),
              SizedBox(height: 16,),
              SubmitButton()
            ],
          ),
        ),
      ),
    );
  }




  Widget NameInput() {
    return TextFormField(
      focusNode: _usernameFocusNode,
      autofocus: true,
      textCapitalization: TextCapitalization.words,
      keyboardType: TextInputType.text ,
      decoration: InputDecoration(
        labelText: "Username",
        hintText: "e.g Morgan",
      ),
      textInputAction: TextInputAction.next,
      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,
      onFieldSubmitted: (_){
        fieldFocusChange(context, _usernameFocusNode, _emailFocusNode);
      },
    );
 }



  Widget EmailInput() {
    return TextFormField(
      focusNode: _emailFocusNode,
      keyboardType: TextInputType.emailAddress ,
      decoration: InputDecoration(
        labelText: "Email",
        hintText: "e.g [email protected]",
      ),
      textInputAction: TextInputAction.next,
      validator: (email)=>EmailValidator.validate(email)? null:"Invalid email address",
      onSaved: (email)=> _email = email,
      onFieldSubmitted: (_){
        fieldFocusChange(context, _emailFocusNode, _passwordFocusNode);
      },
    );
  }

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

      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,
    );
  }



   RaisedButton SubmitButton(){
    return  RaisedButton(
      color:Theme.of(context).primaryColor,
      onPressed: (){
        if(_formKey.currentState.validate()){
          _formKey.currentState.save();
          toastMessage("Username: $_username\nEmail: $_email\nPassword: $_password");
        }
      },
      child: Text("Submit",style: TextStyle(color: Colors.white),),
    );
  }
}

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

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

Congratulation

Image for post
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.

Summery

It’s all About this issue. Hope all solution helped you a lot. Comment below Your thoughts and your queries. Also, Comment below which solution worked for you? Thank You.

Also Read

Leave a Comment