shalini
shalini

Reputation: 2375

Textfield validation in Flutter

I am working on Flutter TextField widget. I want to show an error message below the TextField widget if the user does not fill that TextField. I only have to use TextField Widget not TextFormField in this case.

Upvotes: 134

Views: 291564

Answers (6)

anmol.majhail
anmol.majhail

Reputation: 51326

A Minimal Example of what you Want:

class MyHomePage extends StatefulWidget {
  @override
  MyHomePageState createState() {
    return new MyHomePageState();
  }
}

class MyHomePageState extends State<MyHomePage> {
  final _controller = TextEditingController();
  bool _validate = false;

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('TextField Demo'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text('Error Showed if Field is Empty on Submit button Pressed'),
            TextField(
              controller: _controller,
              decoration: InputDecoration(
                labelText: 'Enter the Value',
                errorText: _validate ? "Value Can't Be Empty" : null,
              ),
            ),
            ElevatedButton(
              onPressed: () {
                setState(() {
                  _validate = _controller.text.isEmpty;
                });
              },
              child: Text('Submit'),
            )
          ],
        ),
      ),
    );
  }
}

Upvotes: 201

O&#39;Prime
O&#39;Prime

Reputation: 101

We can validate user-input in TextField by simply over-riding selected parameters in the InputDecoration widget

Note: Although using the validation methods(save, reset, validate) defined in the FormState object is a popular option for validating forms, this may not be an efficient way.

From the official documentation of GlobalKey:

GlobalKeys should not be re-created on every build. They should usually be long-lived objects owned by a State object, for example. Creating a new GlobalKey on every build will throw away the state of the subtree associated with the old key and create a new fresh subtree for the new key. Besides harming performance, this can also cause unexpected behavior in widgets in the subtree. For example, a GestureDetector in the subtree will be unable to track ongoing gestures since it will be recreated on each build.

The following example shows a simple way of validating the amount entered in field using errorText, errorStyle, and errorBorder parameters.

I am using flutter version: 3.10.0

                TextField(
                  inputFormatters: [
                    FilteringTextInputFormatter.digitsOnly],

                  onChanged: (value) {
                    // This method verifies and validates the user-input based on the conditions defined in it.
                    amountErrorStatus = validateAmount(value);

                    if (!amountErrorStatus) {
                      amountTextEditingController.text = value;

                     // Code to utilise the validated input.   
                    }
                    
                  },
                  controller: amountTextEditingController,
                  decoration: inputDecoration(
                    contentPadding:
                        const EdgeInsets.symmetric(vertical: 10),
                  ).copyWith(

                   // Based on the boolean status indicated by `amountErrorStatus`,
                   // you can choose to display the error message and error border.
                    errorText: amountErrorStatus
                        ? "Your redeem amount cannot be lesser than ₹ 500."
                        : null,
                    errorStyle: TextStyle(
                      fontSize: 14,
                      fontWeight: FontWeight.w400,
                      color: Colors.red[700],
                    ),
                    errorBorder: amountErrorStatus
                        ? OutlineInputBorder(
                            borderRadius: BorderRadius.circular(8),
                            borderSide: BorderSide(
                              color: colors.red[400],
                              width: 1.5,
                            ),
                          )
                        : OutlineInputBorder(
                            borderRadius: BorderRadius.circular(8),
                            borderSide: BorderSide(
                              color: Colors.gray[300],
                              width: 1.5,
                            ),
                         ),
                    ),
                )


void validateAmount(String value) {
bool amountErrorStatus = false;

  if (value.isEmpty) {
    amountErrorStatus = true;
  } 
  else if ((int.tryParse(value) ?? 0) < 500) {
    amountErrorStatus = true;
  } 
  else {
    amountErrorStatus = false;
  }
return amountErrorStatus;
}

Upvotes: 0

Muhammad Mohsin
Muhammad Mohsin

Reputation: 408

For TextFiled and TextFormFiled Validation you can use this Example I hope this will helpful for you people.

                   TextField(
                          enableInteractiveSelection: true,
                          autocorrect: false,
                          enableSuggestions: false,
                          toolbarOptions: ToolbarOptions(
                            copy: false,
                            paste: false,
                            cut: false,
                            selectAll: false,
                          ),
                          controller: _currentPasswordController,
                          obscureText: passwordVisible,
                          decoration: InputDecoration(
                            errorText: Validators.password(
                                _currentPasswordController.text),
                            filled: true,
                            fillColor: Colors.white,
                            contentPadding:
                                const EdgeInsets.fromLTRB(20, 24, 12, 16),
                            border: const OutlineInputBorder(
                                borderRadius:
                                    BorderRadius.all(Radius.circular(8.0))),
                            // filled: true,
                            labelText: 'Password',
                            hintText: 'Enter your password',
                            suffixIcon: GestureDetector(
                              onTap: () {
                                setState(() {
                                  passwordVisible = !passwordVisible;
                                });
                              },
                              child: Container(
                                  margin: const EdgeInsets.all(13),
                                  child: Icon(
                                      passwordVisible
                                          ? FontAwesomeIcons.eyeSlash
                                          : Icons.remove_red_eye_sharp,
                                      color: ColorUtils.primaryGrey,
                                      size: 25)),
                            ),
                          ),
                        ),

Validation Message Example Code

static password(String? txt) {
if (txt == null || txt.isEmpty) {
  return "Invalid password!";
}
if (txt.length < 8) {
  return "Password must has 8 characters";
}
if (!txt.contains(RegExp(r'[A-Z]'))) {
  return "Password must has uppercase";
}
if (!txt.contains(RegExp(r'[0-9]'))) {
  return "Password must has digits";
}
if (!txt.contains(RegExp(r'[a-z]'))) {
  return "Password must has lowercase";
}
if (!txt.contains(RegExp(r'[#?!@$%^&*-]'))) {
  return "Password must has special characters";
} else
  return;
}

Upvotes: 4

Jitesh Mohite
Jitesh Mohite

Reputation: 34270

Flutter handles error text itself, so we don't require to use variable _validate. It will check at runtime whether you satisfied the condition or not.

final confirmPassword = TextFormField(
  controller: widget.confirmPasswordController,
  obscureText: true,
  decoration: InputDecoration(
    prefixIcon: Icon(Icons.lock_open, color: Colors.grey),
    hintText: 'Confirm Password',
    errorText: validatePassword(widget.confirmPasswordController.text),
    contentPadding: EdgeInsets.fromLTRB(20.0, 10.0, 20.0, 10.0),
  ),
);

String validatePassword(String value) {
  if (!(value.length > 5) && value.isNotEmpty) {
    return "Password should contain more than 5 characters";
  }
  return null;
}

Note: User must add at least one character to get this error message.

Upvotes: 42

Om Chevli
Om Chevli

Reputation: 239

  • If you use TextFormField then you could easily implement 'Error below your text fields'.
  • You can do this without using _validate or any other flags.
  • In this example, I have used validator method of TextFormField widget. This makes the work a lot more easier and readable at the same time.
  • I also used FormState to make the work more easier
void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  final _form = GlobalKey<FormState>(); //for storing form state.

//saving form after validation  
void _saveForm() {
    final isValid = _form.currentState.validate();
    if (!isValid) {
      return;
    }
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: Form(
          key: _form, //assigning key to form

          child: ListView(
            children: <Widget>[

              TextFormField(
                decoration: InputDecoration(labelText: 'Full Name'),
                validator: (text) {
                  if (!(text.length > 5) && text.isNotEmpty) {
                    return "Enter valid name of more then 5 characters!";
                  }
                  return null;
                },
              ),

              TextFormField(
                decoration: InputDecoration(labelText: 'Email'),
                validator: (text) {
                  if (!(text.contains('@')) && text.isNotEmpty) {
                    return "Enter a valid email address!";
                  }
                  return null;
                },
              ),

              RaisedButton(
                child: Text('Submit'),
                onPressed: () => _saveForm(),
              )
            ],
          ),
        ),
      ),
    );
  }
}

I hope this helps!

Upvotes: 23

Erlend
Erlend

Reputation: 1969

I would consider using a TextFormField with a validator.

Example:

class MyHomePageState extends State<MyHomePage> {
  final _formKey = GlobalKey<FormState>();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('TextFormField validator'),
      ),
      body: Form(
        key: _formKey,
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            TextFormField(
              decoration: InputDecoration(
                hintText: 'Enter text',
              ),
              textAlign: TextAlign.center,
              validator: (text) {
                if (text == null || text.isEmpty) {
                  return 'Text is empty';
                }
                return null;
              },
            ),
            RaisedButton(
              onPressed: () {
                if (_formKey.currentState.validate()) {
                  // TODO submit
                }
              },
              child: Text('Submit'),
            )
          ],
        ),
      ),
    );
  }
}

Upvotes: 41

Related Questions