i got a problem while trying to make a form validator on my login screen it just doesn t work when i tape login and the text field is already null. here s my code if u have any help, i m down to :
TextFormField validate parameter takes a function that returns null if the content of the field is valid, or a string if the content is invalid. I have null safety in my flutter project and I can't return null from my validate function. How can I write a working validate function with null safety on?
Login code screen :
import 'package:flutter/material.dart';
import 'package:flutter_udemy/shared/components/components.dart';
class LoginScreen extends StatefulWidget {
LoginScreen({Key? key}) : super(key: key);
#override
_LoginScreenState createState() => _LoginScreenState();
}
class _LoginScreenState extends State<LoginScreen> {
var emailController = TextEditingController();
var passwordController = TextEditingController();
var formKey = GlobalKey<FormState>();
bool isPassword = true;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Padding(
padding: const EdgeInsets.all(20.0),
child: Center(
child: SingleChildScrollView(
child: Form(
key: formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Login',
style: TextStyle(
fontSize: 40.0,
fontWeight: FontWeight.bold,
),
),
SizedBox(
height: 40.0,
),
defaultFormField(
controller: emailController,
label: 'Email',
prefix: Icons.email,
type: TextInputType.emailAddress,
validate: (String value) {
if (value.isEmpty) {
return 'email must not be empty';
}
return null;
},
),
SizedBox(
height: 15.0,
),
defaultFormField(
controller: passwordController,
label: 'Password',
prefix: Icons.lock,
suffix:
isPassword ? Icons.visibility : Icons.visibility_off,
isPassword: isPassword,
suffixPressed: () {
setState(() {
isPassword = !isPassword;
});
},
type: TextInputType.visiblePassword,
validate: (String value) {
if (value.isEmpty) {
return 'password is too short';
}
return null;
},
),
SizedBox(
height: 20.0,
),
defaultButton(
text: 'login',
function: () {
if (formKey.currentState!.validate()) {
print(emailController.text);
print(passwordController.text);
}
},
),
SizedBox(
height: 20.0,
),
defaultButton(
text: 'ReGIster',
function: () {
print(emailController.text);
print(passwordController.text);
},
),
SizedBox(
height: 10.0,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'Don\'t have an account?',
),
TextButton(
onPressed: () {},
child: Text(
'Register Now',
),
),
],
),
],
),
),
),
),
),
);
}
}
componenents code screen where i got the button widget and text field widget:
import 'package:flutter/material.dart';
Widget defaultButton({
double width = double.infinity,
Color background = Colors.blue,
bool isUpperCase = true,
double radius = 10.0,
required Function function,
required String text,
}) =>
Container(
width: width,
height: 50.0,
child: MaterialButton(
onPressed: () {
function();
},
child: Text(
isUpperCase ? text.toUpperCase() : text,
style: TextStyle(
color: Colors.white,
),
),
),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(
radius,
),
color: background,
),
);
Widget defaultFormField({
required TextEditingController controller,
required TextInputType type,
Function? onSubmit,
Function? onChange,
bool isPassword = false,
required Function validate,
required String label,
required IconData prefix,
IconData? suffix,
Function? suffixPressed,
}) =>
TextFormField(
controller: controller,
keyboardType: type,
obscureText: isPassword,
onFieldSubmitted: (s) {
onSubmit!(s);
},
onChanged: (s) {
onChange!(s);
},
validator: (s) {
validate(s);
},
decoration: InputDecoration(
labelText: label,
prefixIcon: Icon(
prefix,
),
suffixIcon: suffix != null
? IconButton(
onPressed: () {
suffixPressed!();
},
icon: Icon(
suffix,
),
)
: null,
border: OutlineInputBorder(),
),
);
This code works
Main changes done for null safety
required String? Function(String?)? validate
validate: (String? value) {
if (value!.isEmpty)
{
return 'email must not be empty';
}
return null;
},
Full code below
class LoginScreen extends StatefulWidget {
LoginScreen({Key? key}) : super(key: key);
#override
_LoginScreenState createState() => _LoginScreenState();
}
class _LoginScreenState extends State<LoginScreen> {
var emailController = TextEditingController();
var passwordController = TextEditingController();
final formKey = GlobalKey<FormState>();
bool isPassword = true;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Padding(
padding: const EdgeInsets.all(20.0),
child: Center(
child: SingleChildScrollView(
child: Form(
key: formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Login',
style: TextStyle(
fontSize: 40.0,
fontWeight: FontWeight.bold,
),
),
SizedBox(
height: 40.0,
),
defaultFormField(
controller: emailController,
label: 'Email',
prefix: Icons.email,
type: TextInputType.emailAddress,
validate: (String? value) {
if (value!.isEmpty) {
return 'email must not be empty';
}
return null;
},
),
SizedBox(
height: 15.0,
),
defaultFormField(
controller: passwordController,
label: 'Password',
prefix: Icons.lock,
suffix:
isPassword ? Icons.visibility : Icons.visibility_off,
isPassword: isPassword,
suffixPressed: () {
setState(() {
isPassword = !isPassword;
});
},
type: TextInputType.visiblePassword,
validate: (String? value) {
if (value!.isEmpty) {
return 'password is too short';
}
return null;
},
),
SizedBox(
height: 20.0,
),
defaultButton(
text: 'login',
function: () {
if (formKey.currentState!.validate()) {
print(emailController.text);
print(passwordController.text);
}
},
),
SizedBox(
height: 20.0,
),
defaultButton(
text: 'ReGIster',
function: () {
print(emailController.text);
print(passwordController.text);
},
),
SizedBox(
height: 10.0,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'Don\'t have an account?',
),
TextButton(
onPressed: () {},
child: Text(
'Register Now',
),
),
],
),
],
),
),
),
),
),
);
}
Widget defaultButton({
double width = double.infinity,
Color background = Colors.blue,
bool isUpperCase = true,
double radius = 10.0,
required Function function,
required String text,
}) =>
Container(
width: width,
height: 50.0,
child: MaterialButton(
onPressed: () {
function();
},
child: Text(
isUpperCase ? text.toUpperCase() : text,
style: TextStyle(
color: Colors.white,
),
),
),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(
radius,
),
color: background,
),
);
}
Widget defaultFormField({
required TextEditingController controller,
required TextInputType type,
Function? onSubmit,
Function? onChange,
bool isPassword = false,
required String? Function(String?)? validate,
required String label,
required IconData prefix,
IconData? suffix,
Function? suffixPressed,
}) =>
TextFormField(
controller: controller,
keyboardType: type,
obscureText: isPassword,
onFieldSubmitted: (s) {
onSubmit!(s);
},
onChanged: (s) {
onChange!(s);
},
validator: validate,
decoration: InputDecoration(
labelText: label,
prefixIcon: Icon(
prefix,
),
suffixIcon: suffix != null
? IconButton(
onPressed: () {
suffixPressed!();
},
icon: Icon(
suffix,
),
)
: null,
border: OutlineInputBorder(),
),
);
you can try this one
validate: (String? value) {
if (value == null || value.trim().isEmpty) {
return 'Please provide a value.';
}
return null;
}
Related
import 'package:flutter/material.dart';
import 'package:sumanthk07/utilities/routes.dart';
class LoginPage extends StatefulWidget {
const LoginPage({Key? key}) : super(key: key);
#override
State<LoginPage> createState() => _LoginPageState();
}
class _LoginPageState extends State<LoginPage> {
final _formkey = GlobalKey<FormState>();
// ignore: avoid_types_as_parameter_names, non_constant_identifier_names
moveToHome(BuildContext) async{
Navigator.pushNamed(context, MyRoutes.homeRoute);
}
#override
Widget build(BuildContext context) {
return Material(
color: Colors.white,
child: SingleChildScrollView(
child: Form(
key: _formkey,
child: Column(
children: [
Image.asset("assets/images/login.png", fit: BoxFit.cover),
const SizedBox(
height: 20.0,
),
const Text(
'Welcome',
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
),
const SizedBox(
height: 20.0,
),
Padding(
padding: const EdgeInsets.symmetric(
vertical: 16.0, horizontal: 32.0),
child: Column(
children: [
TextFormField(
decoration: const InputDecoration(
hintText: "Enter User name", labelText: "Username "),
initialValue: "",
validator: (String? value) {
if (value !=null && value.isEmpty ) {
return "User name cannot be empty";
}
return null;
},
onChanged: (value) {
setState(() {});
},
),
TextFormField(
obscureText: true,
decoration: const InputDecoration(
hintText: "Enter password", labelText: "Password "),
initialValue: "",
validator: (String? value) {
if (value !=null && value.isEmpty ) {
return "Password name cannot be empty";
}
return null;
},
),
const SizedBox(
height: 20.0,
),
InkWell(
onTap: () => moveToHome(context),
child: AnimatedContainer(
duration: const Duration(seconds: 1),
height: 40,
width: 80,
alignment: Alignment.center,
child: const Text("Login",
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 18,
)),
decoration: BoxDecoration(
color: Colors.red,
// ignore: unnecessary_const
borderRadius: BorderRadius.circular(20)),
),
)
// ElevatedButton(
// child: const Text("Login"),
// style: TextButton.styleFrom(),
// onPressed: () {
// // ignore: unused_local_variable
// var myRoutes = MyRoutes;
// Navigator.pushNamed(context, MyRoutes.homeRoute);
// },
// )
],
),
)
],
),
),
),
);
}
BorderRadius newMethod() => BorderRadius.circular(20);
}
Hi All, I'm a beginner to flutter and I'm trying to add validator to widget but I'm not getting the validation when I run the application.
I searched and tried the ways to do it but I didn't get the desired outcome.
Can you guys look into my code and suggest the right way.
no errors found but validation is not working.
First assign TextEditingController to your both fields.
final TextEditingController _controllerUserName = TextEditingController();
final TextEditingController _controllerPassword = TextEditingController();
And also assign autovalidateMode to your text field so you can validate at user input like this. It's not necessary it's optional but you can add it to validate your field on input field changes. Although you can validate your form at submission time.
TextFormField(
decoration: const InputDecoration(
hintText: "Enter User name", labelText: "Username "),
initialValue: "",
validator: (String? value) {
if (value !=null && value.isEmpty ) {
return "User name cannot be empty";
}
return null;
},
onChanged: (value) {
setState(() {});
},
autovalidate : AutovalidateMode.onUserInteraction,
controller:_controllerUserName
),
And also you have not validate your form at submission time. try this
moveToHome(BuildContext) async{
if (_formkey.currentState.validate()) {
Navigator.pushNamed(context, MyRoutes.homeRoute);
}
}
I have an issue with my textformfield. Whenever the error message shows, it shifted down the next widget below...
I try to search how to give a placement for the error text to no take a placement that does not exist when it is not shown, but I didn't find the solution.
Here are the screenshot and the code of the issue.
class AuthForm extends StatefulWidget {
final bool isPassword;
final IconData prefixIcon;
final String hintText;
late bool isPasswordVisible = isPassword;
final bool isCalendar;
final TextEditingController controller;
final bool isDropDown;
final bool isPhone;
final String? Function(String?)? validator;
AuthForm({Key? key, this.isPassword = false, required this.prefixIcon, required this.hintText,
this.isCalendar = false, required this.controller, this.isDropDown = false, this.isPhone = false, required this.validator}) : super(key: key);
#override
State<AuthForm> createState() => _AuthFormState();
}
class _AuthFormState extends State<AuthForm> {
#override
void initState() {
super.initState();
if (widget.isPhone){
getCountryCode();
}
}
start () async {
await CountryCodes.init();
}
Locale? getCountryCode () {
start();
final Locale? deviceLocale = CountryCodes.getDeviceLocale();
final CountryDetails details = CountryCodes.detailsForLocale();
return deviceLocale;
}
DateTime selectedDate = DateTime(2000,1);
Future<void> _selectDate(BuildContext context) async {
final DateTime? picked = await showDatePicker(
context: context,
initialDate: selectedDate,
firstDate: DateTime(1950, 1),
lastDate: DateTime.now());
if (picked != null && picked != selectedDate) {
setState(() {
selectedDate = picked;
});
}
}
#override
Widget build(BuildContext context) {
return widget.isDropDown ? const DropDownBar() :
SizedBox(
width: 70.w,
child: TextFormField(
validator: widget.validator,
keyboardType: widget.isPhone ? TextInputType.phone : TextInputType.text,
inputFormatters: [DialCodeFormatter()],
controller: widget.controller,
textAlign: TextAlign.center,
obscureText: widget.isPasswordVisible,
style: Theme.of(context).textTheme.bodyText2,
decoration: InputDecoration(
contentPadding: EdgeInsets.fromLTRB(0, 2.3.h, 0, 0),
hintText : widget.hintText,
hintStyle: Theme.of(context).textTheme.bodyText1,
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(
color: Theme.of(context).splashColor,
width: 0.13.w,
),
),
errorStyle: Theme.of(context).textTheme.headline6,
prefixIcon: Container(
width: 0,
alignment: const Alignment(-0.99, 0.5),
child: Icon(
widget.prefixIcon,
color: Theme.of(context).primaryColor,
size: 6.w,
),
),
suffixIcon: Visibility(
visible: widget.isPassword,
//Maintain the space where the widget is even if it is hid
maintainAnimation: true,
maintainState: true,
maintainSize: true,
child: InkWell(
highlightColor : Colors.transparent,
splashColor: Colors.transparent,
child: Container(
width: 0,
alignment: const Alignment(0.99, 0.5),
child: Icon(
widget.isPasswordVisible ? Icons.visibility : Icons.visibility_off,
color: Theme.of(context).primaryColor,
size: 6.w,
),
),
onTap: () {
setState(() {
widget.isPasswordVisible = !widget.isPasswordVisible;
});
},
),
),
),
onTap: () async {
if (widget.isCalendar){
//Dismiss the keyboard
FocusScope.of(context).requestFocus(FocusNode());
//Call the calendar
await _selectDate(context);
widget.controller.text = DateFormat('dd-MM-yyyy').format(selectedDate);
}
}
),
);
}
}
Login Page
#override
Widget build(BuildContext context) {
return BlocListener<InternetCubit, InternetState>(
listener: (context, state) {
if (state is InternetDisconnected) {
showAlertBox(context);
}
},
child: Form(
key: _formkey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(
height: 6.h,
),
Text(
"Flexmes",
style: Theme.of(context).textTheme.headline1,
),
SizedBox(
height: 8.h,
),
AuthForm(
prefixIcon: Icons.email_outlined,
hintText: "Email",
controller: emailController,
nextFocusNode: passwordNode,
validator: MultiValidator([
RequiredValidator(errorText: 'Email is required'),
EmailValidator(errorText: 'Enter a valid email address'),
]),
),
SizedBox(
height: 3.h,
),
AuthForm(
isPassword: true,
prefixIcon: Icons.lock_rounded,
hintText: "Password",
controller: passwordController,
currentFocusNode: passwordNode,
validator: MultiValidator([
RequiredValidator(errorText: 'Password is required'),
MinLengthValidator(6, errorText: 'Password must be at least 6 digits long'),
PatternValidator(r'(?=.*?[#?!#$%^&*-])', errorText: 'Passwords must have at least one special character')
]),
),
SizedBox(
height: 4.5.h,
),
SizedBox(
width: 70.w,
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
CustomCheckbox(
iconColor: Colors.black,
activeColor: const Color.fromARGB(255, 3, 218, 197),
),
SizedBox(
width: 3.w,
),
Text(
"Remember me",
style: Theme.of(context).textTheme.bodyText2,
)
],
),
),
SizedBox(
height: 4.5.h,
),
AuthButton(
text: "Log In",
onPressed: (){
if (isInternetDisconnected(context)){
showAlertBox(context);
} else{
if (_formkey.currentState!.validate()){
AuthenticationAPI(auth: FirebaseAuth.instance).signInWithEmail(emailController.text, passwordController.text);
//return navigation
}
}
}
),
SizedBox(
height: 3.2.h,
),
ClickableText(
text: "Forgot Password ?",
onPressed: () {
if (isInternetDisconnected(context)){
showAlertBox(context);
} else{
//return navigation
}
},
),
SizedBox(
height: 3.2.h,
),
const AuthDivider(
text: "OR",
),
SizedBox(
height: 2.h,
),
SizedBox(
width: 70.w,
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
ClickableImage(
imagePath: "assets/images/icon/Facebook.png",
width: 23.w,
onPressed: () {
null;
},
),
ClickableImage(
imagePath: "assets/images/icon/Instagram.png",
width: 23.w,
onPressed: () {
null;
},
),
ClickableImage(
imagePath: "assets/images/icon/Tiktok.png",
width: 23.w,
onPressed: () {
null;
},
),
],
),
),
SizedBox(
height: 4.h,
),
SizedBox(
width: 70.w,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"Don't have an account ? ",
style: Theme.of(context).textTheme.bodyText2,
),
ClickableText(
text: 'Sign up Now !',
onPressed: () {
if (isInternetDisconnected(context)){
showAlertBox(context);
} else{
Navigator.of(context).pushNamed("/signup1");
}
},
),
],
),
),
],
),
),
);
}
}
Thanks for your suggestion,
Chris
try wrapping textformfield with container and giving it height and width
Try wrapping TextFormField with container and give it height and width.
Hi I have created a default form field, in a separate dart file called components, and I have login_screen.dart also.
there are many errors I don't know how to fix it, and make the code work, I will put down the code of the component.dart code:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
Widget defaultButton(
{double width = double.infinity,
Color background = Colors.blue,
double radius = 10.0,
required Function function,
required String text,
bool isUpperCase = true}) =>
Container(
height: 40.0,
width: width,
child: MaterialButton(
onLongPress: () {},
onPressed: function(),
child: Text(
isUpperCase ? text.toUpperCase() : text.toLowerCase(),
style: TextStyle(color: Colors.white),
)),
decoration: BoxDecoration(
borderRadius: BorderRadiusDirectional.circular(radius),
color: background,
),
);
Widget defaultFormFeild({
required TextEditingController controller,
required TextInputType type,
Function onSubmit,
Function onChange,
required Function validate,
required var label,
required IconData prefix,
}) =>
TextFormField(
controller: controller,
keyboardType: type,
onFieldSubmitted: onSubmit(),
onChanged: onChange(),
validator: validate(),
decoration: InputDecoration(
labelText: label,
prefixIcon: Icon(prefix),
border: OutlineInputBorder()
),
);
and here is the code of the login_screen.dart:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:udemy_flutter/shared/components/components.dart';
class LoginScreen extends StatelessWidget {
var emailController = TextEditingController();
var passController = TextEditingController();
var formKey = GlobalKey<FormState>();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Padding(
padding: const EdgeInsets.all(20.0),
child: Center(
child: SingleChildScrollView(
child: Form(
key: formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Login',
style: TextStyle(
fontSize: 40.0,
fontWeight: FontWeight.bold
),
),
const SizedBox(
height: 40.0,
),
defaultFormFeild(
controller: emailController,
label: 'Email',
prefix: Icons.email,
type: TextInputType.emailAddress,
validate: (String value){
if(value.isEmpty != null){
return 'Email Cannot Be Empty';
}
return null;
}
),
const SizedBox(
height: 15.0,
),
TextFormField(
controller: passController,
obscureText: true,
keyboardType: TextInputType.visiblePassword,
decoration: const InputDecoration(
border: OutlineInputBorder(),
labelText: 'Password',
prefixIcon: Icon(
Icons.lock
),
suffixIcon: Icon(
Icons.remove_red_eye,
)
),
onChanged: (value) {
print(value);
},
onFieldSubmitted: (value) {
print(value);
},
validator: (value) {
if(value!.isEmpty){
return 'Password cannot be empty';
}
return null;
},
),
const SizedBox(
height: 10.0,
),
defaultButton(
function: (){
print(emailController.text);
print(passController.text);
},
text: 'Login',
),
const SizedBox(
height: 10.0,
),
defaultButton(
text: 'ReGister',
function: () {
print('You have just clicked on register');
},
background: Colors.red,
isUpperCase: false
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text('Don\'t you have an account?'),
TextButton(onPressed: () {}, child: const Text(
'Register Now'
))
],
)
],
),
),
),
),
),
);
}
}
Idk if all the problems came from a null-safety feature in a flutter because I'm new in this technology.
Why
The reason this happens is because with null safety enabled, your functions onSubmit and onChange can't be null.
Solution
I would do it this way:
Widget defaultFormFeild({
required TextEditingController controller,
required TextInputType type,
Function? onSubmit, //Add question mark
Function? onChange, //Add question mark
required Function validate,
required var label,
required IconData prefix,
}) =>
TextFormField(
controller: controller,
keyboardType: type,
onFieldSubmitted: onSubmit != null? onSubmit() : null, //do null checking
onChanged: onChange != null? onChange() : null, //do null checking
validator: validate(),
decoration: InputDecoration(
labelText: label,
prefixIcon: Icon(prefix),
border: OutlineInputBorder()
),
);
I made some TextFormField, and I want to save the data in int when I press the FlatButton. When I press FlatButton, I want him to check whether the sum of TextFormField expenses and savings is not greater than TextFormField income. if the sum of the TextTormField expenses and savings is greater, I want to display errortext under the textformfield savings "your expenses and savings are greater than your income"
class BigNotePage extends StatefulWidget {
#override
_BigNotePageState createState() => _BigNotePageState();
}
class _BigNotePageState extends State<BigNotePage> {
final _formKey = GlobalKey<FormState>();
String _income;
String _expenses;
String _savings;
#override
Widget build(BuildContext context) {
return Container(
padding: kPading,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TitlePage('Big Note'),
Expanded(
child: Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisAlignment: MainAxisAlignment.center,
children: [
TxtField(
label: 'Income',
function: (value) => _income = value,
),
TxtField(
label: 'Expenses',
function: (value) => _expenses = value,
),
TxtField(
label: 'Savings',
function: (value) => _savings = value,
),
FlatButton(
onPressed: () {
int.parse(_income) >=
int.parse(_expenses) + int.parse(_savings)
? _formKey.currentState.save()
: print('null');
},
child: Text(
'WRITE THAT',
style: TextStyle(letterSpacing: 1.25),
),
color: Colors.yellow,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30.0),
),
),
],
),
),
),
Container(
width: 250.0,
child: Text(
'*if you get another income for this mounth, input the income again.',
style: TextStyle(fontSize: 12.0),
),
),
],
),
);
}
}
class TxtField extends StatelessWidget {
TxtField({this.label, this.function});
final String label;
final Function function;
#override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.symmetric(vertical: 8.0),
child: TextFormField(
onSaved: function,
keyboardType: TextInputType.numberWithOptions(decimal: true),
decoration: InputDecoration(
labelText: label,
prefix: Container(
padding: EdgeInsets.all(8.0),
child: Text(
'IDR',
style:
TextStyle(color: Colors.black, fontWeight: FontWeight.bold),
),
),
),
),
);
}
}
Replace String values to the controller values
final _incomeController = TextEditingController();
final _expenseController = TextEditingController();
final _savingController = TextEditingController();
Also, add
bool _validate = false;
Convert String value to int of your TextField:
TextField(
controller: _incomeController,
label: 'Income',
decoration: InputDecoration(
errorText: _validate ? 'Your message' : null,
),
),
TextField(
controller: _expenseController ,
label: 'Expenses',
decoration: InputDecoration(
errorText: _validate ? 'Your message' : null,
),
),
TextField(
controller: _savingController,
label: 'Savings',
decoration: InputDecoration(
errorText: _validate ? 'Your message' : null,
),
),
Now FlatButton Logic:
onPressed: () {
String _income = _incomeController.text;
String _expenses = _expenseController.text;
String _savings = _savingController.text;
int.parse(_income) >=
int.parse(_expenses) + int.parse(_savings)
? _formKey.currentState.save()
: print('null');
},
Rest apply your logic wherever you want.
I am still new to Flutter.In here i want to select the value from a drop down list to the category form field.But i get a error when trying to define
child: DropdownButtonHideUnderline
inside Textformfield.I try to find a solution, but I can't find it and I am not able to program it by myself. I hope you can help me.Is there any other way to archive this?
my codes are here, Thanks in advance for your guidance.
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
final AuthService _auth = AuthService();
final _formKey = GlobalKey<FormState>();
String error = '';
bool loading = false;
String name = '';
String nickname = '';
String city = '';
#override
Widget build(BuildContext context) {
return Container(
child: Scaffold(
backgroundColor: Colors.brown[50],
appBar: AppBar(
title: Text('Brew Crew'),
backgroundColor: Colors.brown[400],
elevation: 0.0,
actions: <Widget>[
FlatButton.icon(
icon: Icon(Icons.person),
label: Text('logout'),
onPressed: () async {
await _auth.signOut();
},
),
],
),
body: Container(
padding: EdgeInsets.symmetric(vertical: 20.0, horizontal: 50.0),
child: Form(
key: _formKey,
child: SingleChildScrollView(
child: Column(
children: <Widget>[
SizedBox(height: 20.0),
TextFormField(
decoration: textInputDecoration.copyWith(hintText: 'Name'),
validator: (val) => val.isEmpty ? 'Enter your name' : null,
onChanged: (val) {
setState(() => name = val);
},
),
SizedBox(height: 20.0),
TextFormField(
decoration: textInputDecoration.copyWith(hintText: 'NickName'),
onChanged: (val) {
setState(() => nickname = val);
},
),
SizedBox(height: 20.0),
TextFormField(
decoration: textInputDecoration.copyWith(hintText: 'City'),
validator: (val) => val.isEmpty ? 'Enter your city' : null,
onChanged: (val) {
setState(() => city = val);
},
),
SizedBox(height: 20.0),
TextFormField(
decoration: textInputDecoration.copyWith(hintText: 'Category'),
validator: (val) => val.isEmpty ? 'Please select a category' : null,
onChanged: (val) {
setState(() => nickname = val);
},
),
SizedBox(height: 20.0),
RaisedButton(
color: Colors.pink[400],
child: Text(
'Submit',
style: TextStyle(color: Colors.white),
),
onPressed: () async {
}
),
SizedBox(height: 12.0),
Text(
error,
style: TextStyle(color: Colors.red, fontSize: 14.0),
)
],
),
),
),
),
),
);
}
}
The problem here is that you do not need a TextFormField, you would require a DropdownButton Widget.
DropdownButton(
items: <DropdownMenuItem>[
DropdownMenuItem(
child: Text("Category I"),
),
DropdownMenuItem(
child: Text("Category II"),
),
],
onChanged: (value) {
},
),
I created you a codepen for that:
https://codepen.io/md-weber/pen/zYvqaGv