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()
),
);
Related
I have screen which have username field,
Here, When i press the submit button add new TextFormField below the UserName field so how i can do this?
Code as Below.
return Container(
child: Form(
key: _formKey,
child: Column(
children: [
Container(
padding: const EdgeInsets.all(10),
child: Text("Reset Password"),
),
Container(
child: Center(
child: Expanded(
child: Text(
"Enter your username below to recieve password reset instruction",
textAlign: TextAlign.center,
maxLines: 2,
),
),
),
),
TextFormField(
controller: userNameController,
textInputAction: TextInputAction.next,
keyboardType: TextInputType.text,
decoration: InputDecoration(
labelText: "User Name",
),
focusNode: fnField1,
validator: (value) {
if (value?.isEmpty == true) {
return AppLocalizations.of(context)!.valEnterUserName;
}
return null;
},
),
Container(
constraints: const BoxConstraints(minWidth: double.infinity),
child: ElevatedButton(
onPressed: () async {},
child: Text("Submit"),
),
),
],
),
),
);
Please help me that how i can do this.
In such a case we can use a StatefulWidget to set a _displayNewTextField boolean to true once the button is pressed:
bool _displayNewTextField = false;
...
Container(
constraints: const BoxConstraints(minWidth: double.infinity),
child: ElevatedButton(
onPressed: () async {
setState(() {
_displayNewTextField = true;
});
},
child: const Text("Submit"),
),
),
And use a Visibility Widget to show the new TextField accordingly:
Visibility(
visible: _displayNewTextField,
child: TextFormField(
controller: newTextFieldController,
textInputAction: TextInputAction.next,
keyboardType: TextInputType.text,
decoration: const InputDecoration(
labelText: "User Name",
),
),
),
A full example is reported below:
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key}) : super(key: key);
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
bool _displayNewTextField = false;
TextEditingController newTextFieldController = TextEditingController();
TextEditingController userNameController = TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Form(
child: Column(
children: [
Container(
padding: const EdgeInsets.all(10),
child: const Text("Reset Password"),
),
const Center(
child: Expanded(
child: Text(
"Enter your username below to recieve password reset instruction",
textAlign: TextAlign.center,
maxLines: 2,
),
),
),
TextFormField(
controller: userNameController,
textInputAction: TextInputAction.next,
keyboardType: TextInputType.text,
decoration: const InputDecoration(
labelText: "User Name",
),
),
Visibility(
visible: _displayNewTextField,
child: TextFormField(
controller: newTextFieldController,
textInputAction: TextInputAction.next,
keyboardType: TextInputType.text,
decoration: const InputDecoration(
labelText: "User Name",
),
),
),
Container(
constraints: const BoxConstraints(minWidth: double.infinity),
child: ElevatedButton(
onPressed: () async {
setState(() {
_displayNewTextField = true;
});
},
child: const Text("Submit"),
),
),
],
),
),
),
);
}
}
import 'package:flutter/material.dart';
import 'package:mmitra/widgets/header.dart';
import 'home.dart';
class CreateAccount extends StatefulWidget {
#override
_CreateAccountState createState() => _CreateAccountState();
}
class _CreateAccountState extends State<CreateAccount> {
late String username;
final _key = Global Key<FormState>();
#override
Widget build(BuildContext parentContext) {
return Scaffold(
appBar: header(context, titleText: 'Create Account'),
body: ListView(children: [
Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Padding(
padding: EdgeInsets.only(top: 25),
child: Center(
child: Text(
'Create a username',
style: TextStyle(fontSize: 25.0),
),
),
),
Padding(
padding: EdgeInsets.all(16.0),
child: Form(
child: TextFormField(
key: _key,
// controller: myController,
onSaved: (val) => username = val!,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelStyle: TextStyle(fontSize: 15),
labelText: 'Username',
hintText: 'Must be at least 3 Characters'),
),
),
),
GestureDetector(
onTap: () {
_key.currentState!.save();
Navigator.pop(context, username
);
},
child: Container(
height: 50,
width: 300,
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.circular(7)),
child: Center(
child: Text(
'Submit',
style:
TextStyle(fontSize: 15, fontWeight: FontWeight.bold),
),
),
),
),
],
),
),
]),
);
}
}
and I'm getting below shown errors:
Exception caught by gesture
The following Cast Error was thrown while handling a gesture
Null check operator used on a null value
I just want to get the textfromfield value and i want to pass it to the home.dart page in order to create the document in firebase collection
you must define a EditTextControll() ex:textController and set it to TextFormField to controller paramerter , and then get text as textController.text and pass with Navigatoer .
for pass wihtin first screen to two screen
Firstly /
TextEditingController controller = TextEditingController();
Secoundly /
body: Form(
child: TextFormField(
controller: controller,
onTap: (){
//here SettingsScreen() is example
// name is paramerter in the secound screen
Navigator.push(context,
MaterialPageRoute(builder: (context)=>SettingsScreen(name:controller.text),),
);
},
),
),
You added key in TextFormField
Form(
child: TextFormField(
key: _key,
// controller: myController,
onSaved: (val) => username = val!,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelStyle: TextStyle(fontSize: 15),
labelText: 'Username',
hintText: 'Must be at least 3 Characters'),
),
),
),
Remove it from TextFormField and Add it in Form
Just Like:
Form(
key: _key,
child: TextFormField(
// controller: myController,
onSaved: (val) => username = val!,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelStyle: TextStyle(fontSize: 15),
labelText: 'Username',
hintText: 'Must be at least 3 Characters'),
),
),
),
This will Solve your Issue.
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;
}
I'm trying to validate two different TextFormFields in two widgets (One for Email, another one for password) with a single _formkey in a flutter. it gave me this error: Multiple widgets used the same GlobalKey. So defined two _formkey but the problem is Flutter form validators don't validate, simultaneously:
class _RegisterState extends State<Register> {
String email = "";
String password = "";
String error = "";
final _formKey1 = GlobalKey<FormState>();
final _formKey2 = GlobalKey<FormState>();
// bool _rememberMe = false;
Widget _buildEmailTF() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
'Email',
style: kLabelStyle,
),
SizedBox(height: 10.0),
Form(
key: _formKey1,
child: Container(
alignment: Alignment.centerLeft,
decoration: kBoxDecorationStyle,
height: 60.0,
child: TextFormField(
validator: (value) => value.isEmpty ? "Enter an Email" : null,
onChanged: (value) {
setState(() {
email = value;
});
},
style: TextStyle(
color: Colors.white,
fontFamily: 'OpenSans',
),
decoration: InputDecoration(
border: InputBorder.none,
contentPadding: EdgeInsets.only(top: 14.0),
prefixIcon: Icon(
Icons.email,
color: Colors.white,
),
hintText: 'Enter your Email',
hintStyle: kHintTextStyle,
),
),
),
),
],
);
}
Widget _buildPasswordTF() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
'Password',
style: kLabelStyle,
),
SizedBox(height: 10.0),
Form(
key: _formKey2,
child: Container(
alignment: Alignment.centerLeft,
decoration: kBoxDecorationStyle,
height: 60.0,
child: TextFormField(
validator: (value) =>
value.length < 6 ? "More than 6 Character" : null,
onChanged: (value) {
setState(() {
password = value;
});
},
obscureText: true,
style: TextStyle(
color: Colors.white,
fontFamily: 'OpenSans',
),
decoration: InputDecoration(
border: InputBorder.none,
contentPadding: EdgeInsets.only(top: 14.0),
prefixIcon: Icon(
Icons.lock,
color: Colors.white,
),
hintText: 'Enter your Password',
hintStyle: kHintTextStyle,
),
),
),
),
],
);
}
and then :
onPressed: () async {
if (_formKey1.currentState.validate() &&
_formKey2.currentState.validate()) {
dynamic result =
await _auth.signUpWithEmailandPassword(email, password);
if (result == null) {
setState(() => error = "Something is wrong");
}
}
},
Just remember that you need one Form Widget above in the widget Tree.
And thus you can use the _formKey to validate multiple TextFormField below in the Widget Tree.
Modified Code
class _RegisterPageState extends State<RegisterPage> {
String email = "";
String password = "";
String error = "";
final _formKey1 = GlobalKey<FormState>();
// final _formKey2 = GlobalKey<FormState>();
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: Form(
key: _formKey1,
child: Container(
child: Column(
children: [
_buildEmailTF(),
SizedBox(
height: 20,
),
_buildPasswordTF(),
FlatButton(
onPressed: () async {
if (_formKey1.currentState.validate()) {
// dynamic result = await _auth.signUpWithEmailandPassword(
// email, password);
// if (result == null) {
// setState(() => error = "Something is wrong");
// }
print('DOne Working');
}
},
child: Text(
'Done',
))
],
),
),
),
);
}
// bool _rememberMe = false;
Widget _buildEmailTF() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
'Email',
),
SizedBox(height: 10.0),
Container(
alignment: Alignment.centerLeft,
height: 60.0,
child: TextFormField(
validator: (value) => value.isEmpty ? "Enter an Email" : null,
onChanged: (value) {
setState(() {
email = value;
});
},
style: TextStyle(
color: Colors.white,
fontFamily: 'OpenSans',
),
decoration: InputDecoration(
border: InputBorder.none,
contentPadding: EdgeInsets.only(top: 14.0),
prefixIcon: Icon(
Icons.email,
color: Colors.white,
),
hintText: 'Enter your Email',
),
),
),
],
);
}
Widget _buildPasswordTF() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
'Password',
),
SizedBox(height: 10.0),
Container(
alignment: Alignment.centerLeft,
height: 60.0,
child: TextFormField(
validator: (value) =>
value.length < 6 ? "More than 6 Character" : null,
onChanged: (value) {
setState(() {
password = value;
});
},
obscureText: true,
style: TextStyle(
color: Colors.white,
fontFamily: 'OpenSans',
),
decoration: InputDecoration(
border: InputBorder.none,
contentPadding: EdgeInsets.only(top: 14.0),
prefixIcon: Icon(
Icons.lock,
color: Colors.white,
),
hintText: 'Enter your Password',
),
),
),
],
);
}
}
I/flutter (24750): DOne Working
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.