I have a flutter TextField which is not embedded in a Form. I want to show and hide an error message, and also have the TextField move in and out of an error state.
When I set the errorMessage property on the TextField it correctly shows the error message and the TextField is given a redline under it to show it's in an error state.
But when I set the error message to null, the error message disappears as expected, but the TextField continues to show a red line under it.
How do I reset the error state of the TextField so it doesn't show the red line under it?
Here is my code.
class _EmailTextFieldState extends State<EmailTextField> {
static const borderColor = Color.fromARGB(255, 84, 160, 246);
#override
Widget build(BuildContext context) {
return BlocBuilder<CustomLoginScreenBloc, CustomLoginScreenState>(
builder: (context, state) {
return Padding(
padding: const EdgeInsets.fromLTRB(30, 30, 30, 20),
child: TextField(
onChanged: (text) {
context
.read<CustomLoginScreenBloc>()
.add(EmailTextChanged(email: text));
},
style: const TextStyle(fontSize: 14),
obscureText: false,
decoration: InputDecoration(
// icon: Icon(Icons.email_outlined),
prefixIcon: const Icon(Icons.email_outlined),
filled: true,
fillColor: const Color.fromRGBO(238, 244, 251, 1),
errorText: state.validationErrorMessage,
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(8.0)),
borderSide: BorderSide(
color: borderColor, width: 0.1, style: BorderStyle.solid),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(8.0)),
borderSide: BorderSide(
color: borderColor, width: 0.5, style: BorderStyle.solid),
),
errorBorder: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(8.0)),
borderSide: BorderSide(
color: borderColor, width: 0.1, style: BorderStyle.solid),
),
disabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(8.0)),
borderSide: BorderSide(
color: borderColor, width: 0.1, style: BorderStyle.solid),
),
labelText: 'email'),
),
);
});
}
}
As the image is shown below, the first image displays my text field before I click on it. the second image displays how it displays when after start typing and clicking on it. I want to remove that label text display while typing. how can I do that?
TextFormField(
controller: usernameEditingController,
decoration: InputDecoration(
fillColor: textWhite,
filled: true,
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(20.0),
borderSide: const BorderSide(
color: textdarkBlue,
),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(20.0),
borderSide: const BorderSide(
color: textdarkBlue,
),
),
errorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(20.0),
borderSide: const BorderSide(color: Colors.red),
),
focusedErrorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(20.0),
borderSide: const BorderSide(color: Colors.red),
),
isDense: true,
contentPadding: EdgeInsets.fromLTRB(10, 30, 10, 0),
labelText: "User Name",
labelStyle: TextStyle(
fontSize: 15,
color: textdarkBlue,
),
hintText: "ex: James",
hintStyle: TextStyle(
color: textdarkBlue,
fontFamily: "Paralucent",
fontSize: 14)),
style: TextStyle(
color: textdarkBlue,
),
validator: (text) {
if (text!.isEmpty) {
return "Username can't be empty";
} else {
return null;
}
},
onChanged: (String? text) {
userName = text!;
//print(userName);
},
),
It is displaying as OutlineInputBorder's behavior.
There are few different ways, One is using FocusNode, goal is to provide labelText:null on focus change.
String userName = "";
late FocusNode focusNode = FocusNode()
..addListener(() {
setState(() {});
});
.....
TextFormField(
// controller: usernameEditingController,
focusNode: focusNode,
decoration: InputDecoration(
labelText: focusNode.hasFocus ? null : "User Name",
That is the behaviour of labelText property if you don't want it , simply remove it and use hintText instead
TextFormField(
controller: usernameEditingController,
decoration: InputDecoration(
fillColor: textWhite,
filled: true,
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(20.0),
borderSide: const BorderSide(
color: textdarkBlue,
),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(20.0),
borderSide: const BorderSide(
color: textdarkBlue,
),
),
errorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(20.0),
borderSide: const BorderSide(color: Colors.red),
),
focusedErrorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(20.0),
borderSide: const BorderSide(color: Colors.red),
),
isDense: true,
contentPadding: EdgeInsets.fromLTRB(10, 30, 10, 0),
hintText: "ex: James",
hintStyle: TextStyle(
color: textdarkBlue,
fontFamily: "Paralucent",
fontSize: 14)),
style: TextStyle(
color: textdarkBlue,
),
validator: (text) {
if (text!.isEmpty) {
return "Username can't be empty";
} else {
return null;
}
},
onChanged: (String? text) {
userName = text!;
//print(userName);
},
),
This is my code for my UI
Container(
padding: EdgeInsets.fromLTRB(10, 10, 10, 0),
child:TextFormField(
controller: name,
textInputAction: TextInputAction.next,
decoration: InputDecoration(
prefixIcon: Icon(
Icons.person,
),
hintText: "First name",
border: OutlineInputBorder(
borderSide: BorderSide(color: Colors.purpleAccent),
borderRadius: BorderRadius.circular(10),
),
),
),
),
Container(
padding: EdgeInsets.fromLTRB(10, 10, 10, 0),
child:TextFormField(
controller: second_name,
textInputAction: TextInputAction.next,
decoration: InputDecoration(
prefixIcon: Icon(
Icons.person,
),
hintText: "Second Name",
border: OutlineInputBorder(
borderSide: BorderSide(color: Colors.purpleAccent),
borderRadius: BorderRadius.circular(10),
),
),
),
),
Container(
padding: EdgeInsets.fromLTRB(10, 10, 10, 0),
child:TextFormField(
textInputAction: TextInputAction.next,
decoration: InputDecoration(
prefixIcon: Icon(
Icons.mail,
),
hintText: "Email-id ",
border: OutlineInputBorder(
borderSide: BorderSide(color: Colors.purpleAccent),
borderRadius: BorderRadius.circular(10),
),
),
),
), Container(
padding: EdgeInsets.fromLTRB(10, 10, 10, 0),
child:TextFormField(
textInputAction: TextInputAction.next,
decoration: InputDecoration(
prefixIcon: Icon(
Icons.vpn_key,
),
hintText: "Password",
border: OutlineInputBorder(
borderSide: BorderSide(color: Colors.purpleAccent),
borderRadius: BorderRadius.circular(10),
),
),
),
), Container(
padding: EdgeInsets.fromLTRB(10, 10, 10, 0),
child:TextFormField(
textInputAction: TextInputAction.next,
decoration: InputDecoration(
prefixIcon: Icon(
Icons.vpn_key,
),
hintText: "Confirm Password",
border: OutlineInputBorder(
borderSide: BorderSide(color: Colors.purpleAccent),
borderRadius: BorderRadius.circular(10),
),
),
),
),
Now there is a sign-up button down this, now i want to show a text at bottom of each container after user enter some data and if the data is not according to some given condition like 'password doesn't match' , so how to show that or what to execute in onpressed function in my button.
please provide some code for this.
Thanks in advance.
This is a sample picture , so the text in red color saying 'This eamil does not exist....' how want to show a text like this ..
In TextFormField, there's a validator function. You can use that to show error messages.
Container(
padding: EdgeInsets.fromLTRB(10, 10, 10, 0),
child:TextFormField(
controller: name,
validator: (value){
if(value== null || value.isEmpty){
return 'Name must not be empty';
}
return null;
}
textInputAction: TextInputAction.next,
decoration: InputDecoration(
prefixIcon: Icon(
Icons.person,
),
hintText: "First name",
border: OutlineInputBorder(
borderSide: BorderSide(color: Colors.purpleAccent),
borderRadius: BorderRadius.circular(10),
),
),
),
),
You can also wrap your entire screen in a Form widget and use key: property to validate when user click on the button. You still have to pass validator function in TextFormField. Form widget is just an extension of validator function feature.
final _formKey = GlobalKey<FormState>();
Form(
key: _formKey,
)
Then add onChanged in your button this code so that without validation the form won't submit.
onChanged: () {
if (!_formKey.currentState!.validate()) {
return;
}
// write code to save inputs here
}
or,
You can also add autovalidateMode: AutovalidateMode.always in TextFormField with validator function to validate form on user interaction. This property is also available in Form widget.
You can use onChanged property.
onChanged: (text) {
}
Please refer to below code
You can try either of the solutions
Solution 1: Autovalidation is disabled and only on user interaction, i.e on click of validate button text form field starts validation accordingly.
class MainScreen extends StatelessWidget {
MainScreen({Key key}) : super(key: key);
final TextEditingController addressController = TextEditingController();
final FocusNode addressFocus = FocusNode();
final TextEditingController stateController = TextEditingController();
final FocusNode stateFocus = FocusNode();
final _validationKey = GlobalKey<FormState>();
int validateAddress(String address) {
String patttern = r'(^[a-zA-Z0-9 ,.-]*$)';
RegExp regExp = new RegExp(patttern);
if (address.isEmpty || address.length == 0) {
return 1;
} else if (address.length < 10) {
return 3;
} else {
return 0;
}
}
int validateState(String state) {
String patttern = r'(^[a-zA-Z0-9 ,.-]*$)';
RegExp regExp = new RegExp(patttern);
if (state.isEmpty || state.length == 0) {
return 1;
} else {
return 0;
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.lightBlue,
automaticallyImplyLeading: true,
leading: Icon(
Icons.arrow_back,
),
title: Text("Example"),
centerTitle: true,
),
body: Container(
padding: EdgeInsets.all(15.0),
child: Column(
children: [
Form(
key: _validationKey,
child: Column(
children: [
/* State */
TextFormField(
autovalidateMode: AutovalidateMode.onUserInteraction,
/* autovalidate is disabled */
controller: stateController,
inputFormatters: [
FilteringTextInputFormatter.deny(RegExp(r"\s\s")),
FilteringTextInputFormatter.deny(RegExp(
r'(\u00a9|\u00ae|[\u2000-\u3300]|\ud83c[\ud000-\udfff]|\ud83d[\ud000-\udfff]|\ud83e[\ud000-\udfff])')),
],
keyboardType: TextInputType.text,
maxLength: 160,
onChanged: (val) {},
maxLines: 1,
validator: (value) {
int res = validateAddress(value);
if (res == 1) {
return "Please enter state";
} else {
return null;
}
},
focusNode: stateFocus,
autofocus: false,
decoration: InputDecoration(
errorMaxLines: 3,
counterText: "",
filled: true,
fillColor: Colors.white,
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(4)),
borderSide: BorderSide(
width: 1,
color: Color(0xffE5E5E5),
),
),
disabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(4)),
borderSide: BorderSide(
width: 1,
color: Color(0xffE5E5E5),
),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(4)),
borderSide: BorderSide(
width: 1,
color: Color(0xffE5E5E5),
),
),
border: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(4)),
borderSide: BorderSide(
width: 1,
),
),
errorBorder: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(4)),
borderSide: BorderSide(
width: 1,
color: Colors.red,
)),
focusedErrorBorder: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(4)),
borderSide: BorderSide(
width: 1,
color: Colors.red,
),
),
hintText: "Enter state" ?? "",
),
),
SizedBox(
height: 15.0,
),
/* Address */
TextFormField(
autovalidateMode: AutovalidateMode.onUserInteraction,
/* autovalidate is disabled */
controller: addressController,
inputFormatters: [
FilteringTextInputFormatter.deny(RegExp(r"\s\s")),
FilteringTextInputFormatter.deny(RegExp(
r'(\u00a9|\u00ae|[\u2000-\u3300]|\ud83c[\ud000-\udfff]|\ud83d[\ud000-\udfff]|\ud83e[\ud000-\udfff])')),
],
keyboardType: TextInputType.text,
maxLength: 60,
onChanged: (val) {},
maxLines: 1,
validator: (value) {
int res = validateAddress(value);
if (res == 1) {
return "Please enter address";
} else if (res == 3) {
return "Please enter minimum 10 characters";
} else {
return null;
}
},
focusNode: addressFocus,
autofocus: false,
decoration: InputDecoration(
errorMaxLines: 3,
counterText: "",
filled: true,
fillColor: Colors.white,
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(4)),
borderSide: BorderSide(
width: 1,
color: Color(0xffE5E5E5),
),
),
disabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(4)),
borderSide: BorderSide(
width: 1,
color: Color(0xffE5E5E5),
),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(4)),
borderSide: BorderSide(
width: 1,
color: Color(0xffE5E5E5),
),
),
border: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(4)),
borderSide: BorderSide(
width: 1,
),
),
errorBorder: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(4)),
borderSide: BorderSide(
width: 1,
color: Colors.red,
)),
focusedErrorBorder: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(4)),
borderSide: BorderSide(
width: 1,
color: Colors.red,
),
),
hintText: "Enter address" ?? "",
),
),
],
),
),
SizedBox(
height: 15.0,
),
OutlinedButton(
onPressed: () {
_validationKey.currentState.validate();
if (stateController.text.isEmpty) {
stateFocus.requestFocus();
} else if (addressController.text.isEmpty ||
addressController.text.length < 10) {
addressFocus.requestFocus();
}
},
child: Text("Validate"),
)
],
),
),
);
}
}
Solution 2: Autovalidation is enabled always
class HomeScreen extends StatelessWidget {
HomeScreen({Key key}) : super(key: key);
final TextEditingController addressController = TextEditingController();
final FocusNode addressFocus = FocusNode();
final TextEditingController stateController = TextEditingController();
final FocusNode stateFocus = FocusNode();
final _validationKey = GlobalKey<FormState>();
int validateAddress(String address) {
String patttern = r'(^[a-zA-Z0-9 ,.-]*$)';
RegExp regExp = new RegExp(patttern);
if (address.isEmpty || address.length == 0) {
return 1;
} else if (address.length < 10) {
return 3;
} else {
return 0;
}
}
int validateState(String state) {
String patttern = r'(^[a-zA-Z0-9 ,.-]*$)';
RegExp regExp = new RegExp(patttern);
if (state.isEmpty || state.length == 0) {
return 1;
} else {
return 0;
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.lightBlue,
automaticallyImplyLeading: true,
leading: Icon(
Icons.arrow_back,
),
title: Text("Example"),
centerTitle: true,
),
body: Container(
padding: EdgeInsets.all(15.0),
child: Column(
children: [
Form(
key: _validationKey,
child: Column(
children: [
/* State */
TextFormField(
autovalidateMode: AutovalidateMode.always,
/* autovalidate is set to true */
controller: stateController,
inputFormatters: [
FilteringTextInputFormatter.deny(RegExp(r"\s\s")),
FilteringTextInputFormatter.deny(RegExp(
r'(\u00a9|\u00ae|[\u2000-\u3300]|\ud83c[\ud000-\udfff]|\ud83d[\ud000-\udfff]|\ud83e[\ud000-\udfff])')),
],
keyboardType: TextInputType.text,
maxLength: 160,
onChanged: (val) {},
maxLines: 1,
validator: (value) {
int res = validateAddress(value);
if (res == 1) {
return "Please enter state";
} else {
return null;
}
},
focusNode: stateFocus,
autofocus: false,
decoration: InputDecoration(
errorMaxLines: 3,
counterText: "",
filled: true,
fillColor: Colors.white,
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(4)),
borderSide: BorderSide(
width: 1,
color: Color(0xffE5E5E5),
),
),
disabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(4)),
borderSide: BorderSide(
width: 1,
color: Color(0xffE5E5E5),
),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(4)),
borderSide: BorderSide(
width: 1,
color: Color(0xffE5E5E5),
),
),
border: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(4)),
borderSide: BorderSide(
width: 1,
),
),
errorBorder: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(4)),
borderSide: BorderSide(
width: 1,
color: Colors.red,
)),
focusedErrorBorder: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(4)),
borderSide: BorderSide(
width: 1,
color: Colors.red,
),
),
hintText: "Enter state" ?? "",
),
),
SizedBox(
height: 15.0,
),
/* Address */
TextFormField(
autovalidateMode: AutovalidateMode.always,
/* autovalidate is enabled */
controller: addressController,
inputFormatters: [
FilteringTextInputFormatter.deny(RegExp(r"\s\s")),
FilteringTextInputFormatter.deny(RegExp(
r'(\u00a9|\u00ae|[\u2000-\u3300]|\ud83c[\ud000-\udfff]|\ud83d[\ud000-\udfff]|\ud83e[\ud000-\udfff])')),
],
keyboardType: TextInputType.text,
maxLength: 60,
onChanged: (val) {},
maxLines: 1,
validator: (value) {
int res = validateAddress(value);
if (res == 1) {
return "Please enter address";
} else if (res == 3) {
return "Please enter minimum 10 characters";
} else {
return null;
}
},
focusNode: addressFocus,
autofocus: false,
decoration: InputDecoration(
errorMaxLines: 3,
counterText: "",
filled: true,
fillColor: Colors.white,
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(4)),
borderSide: BorderSide(
width: 1,
color: Color(0xffE5E5E5),
),
),
disabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(4)),
borderSide: BorderSide(
width: 1,
color: Color(0xffE5E5E5),
),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(4)),
borderSide: BorderSide(
width: 1,
color: Color(0xffE5E5E5),
),
),
border: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(4)),
borderSide: BorderSide(
width: 1,
),
),
errorBorder: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(4)),
borderSide: BorderSide(
width: 1,
color: Colors.red,
)),
focusedErrorBorder: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(4)),
borderSide: BorderSide(
width: 1,
color: Colors.red,
),
),
hintText: "Enter address" ?? "",
),
),
],
),
),
SizedBox(
height: 15.0,
),
],
),
),
);
}