Reputation: 2375
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
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
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
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
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
Reputation: 239
TextFormField
then you could easily implement 'Error
below your text fields'._validate
or any other flags.validator
method of TextFormField
widget. This makes the work a lot more easier and readable at the
same time.FormState
to make the work more easiervoid 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
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