Related
I'm making an app using Flutter which calculates motor vehicle tax.
It calculates it perfectly fine when I enter the cost of vehicle.
But I want to add a validation to it. When I don't enter any cost of vehicle and keeps it empty and then click the calculate button, I want it show - please enter the cost.
How do I add this validation as this is not a form.
Here is the code of that part:
TextField(
controller: costController,
decoration: const InputDecoration(labelText: "Cost of Vehicle"),
keyboardType: TextInputType.number,
inputFormatters: <TextInputFormatter>[
FilteringTextInputFormatter.digitsOnly
],
),
const SizedBox(
height: 20,
),
ElevatedButton(
style: ElevatedButton.styleFrom(
primary: Theme.of(context).primaryColor,
),
onPressed: () {
setState(() {
toPrint = calc(
dropDownValue!,
int.parse(costController.text),
).toString();
});
},
child: const Text("Calculate")),
const SizedBox(
height: 20,
),
Container(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
decoration: BoxDecoration(
color: Colors.lightGreenAccent[100],
border: const Border(
bottom: BorderSide(color: Colors.grey),
)),
child: Text("Tax : $toPrint "),
),
Wrap the column with a Form widget add avalidator to the textfield
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
#override
Widget build(BuildContext context) {
const appTitle = 'Form Validation Demo';
return MaterialApp(
title: appTitle,
home: Scaffold(
appBar: AppBar(
title: const Text(appTitle),
),
body: const MyCustomForm(),
),
);
}
}
// Create a Form widget.
class MyCustomForm extends StatefulWidget {
const MyCustomForm({super.key});
#override
MyCustomFormState createState() {
return MyCustomFormState();
}
}
// Create a corresponding State class.
// This class holds data related to the form.
class MyCustomFormState extends State<MyCustomForm> {
// Create a global key that uniquely identifies the Form widget
// and allows validation of the form.
//
// Note: This is a GlobalKey<FormState>,
// not a GlobalKey<MyCustomFormState>.
final _formKey = GlobalKey<FormState>();
#override
Widget build(BuildContext context) {
// Build a Form widget using the _formKey created above.
return Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TextField(
controller: costController,
decoration: const InputDecoration(labelText: "Cost of Vehicle"),
keyboardType: TextInputType.number,
inputFormatters: <TextInputFormatter>[
FilteringTextInputFormatter.digitsOnly
],
// The validator receives the text that the user has entered.
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please enter some text';
}
return null;
},
),
ElevatedButton(
style: ElevatedButton.styleFrom(
primary: Theme.of(context).primaryColor,
),
onPressed: () {
if (_formKey.currentState!.validate()) {
setState(() {
toPrint = calc(
dropDownValue!, int.parse(costController.text),
).toString();
});
}
},
child: const Text("Calculate")),
const SizedBox(
height: 20,
),
Container(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
decoration: BoxDecoration(
color: Colors.lightGreenAccent[100],
border: const Border(
bottom: BorderSide(color: Colors.grey),
)),
child: Text("Tax : $toPrint "),
),
],
),
);
}
}
Use Form Widget and Convert TextField to TextFormField like that.
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class FormWidget extends StatefulWidget {
const FormWidget({Key? key}) : super(key: key);
#override
State<FormWidget> createState() => _FormWidgetState();
}
class _FormWidgetState extends State<FormWidget> {
final TextEditingController costController = TextEditingController();
final _formKey = GlobalKey<FormState>();
#override
Widget build(BuildContext context) {
return Scaffold(
key: _formKey,
body: Column(
children: [
Form(
child: TextFormField(
validator: (value) {
if (value.isEmpty) {
return "Please enter the cost.";
}
return null;
},
controller: costController,
decoration: const InputDecoration(labelText: "Cost of Vehicle"),
keyboardType: TextInputType.number,
inputFormatters: <TextInputFormatter>[
FilteringTextInputFormatter.digitsOnly
],
),
),
const SizedBox(
height: 20,
),
ElevatedButton(
style: ElevatedButton.styleFrom(
primary: Theme.of(context).primaryColor,
),
onPressed: () {
if(_formKey.currentState.validate()){
//do your setState stuff
setState(() {
});
}
},
child: const Text("Calculate")),
const SizedBox(
height: 20,
),
Container(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
decoration: BoxDecoration(
color: Colors.lightGreenAccent[100],
border: const Border(
bottom: BorderSide(color: Colors.grey),
)),
child: Text("Tax : "),
),
],
),
);
}
}
I am implementing AnimatedList on my app with several TextEditingControllers. I would like to dynamically update, insert and remove data. I've read this question and an article on how to update data in an AnimatedList and this is how my code looks:
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
#override
State<StatefulWidget> createState() => _HomePage();
}
class _HomePage extends State<HomePage> {
List<Board> boards = [Board.empty()];
final GlobalKey<AnimatedListState> listKey = GlobalKey<AnimatedListState>();
void Function()? removeItemCallback(int index) {
if (boards.length <= 1) {
return null;
}
return (() {
FocusManager.instance.primaryFocus?.unfocus();
final removedBoard = boards.removeAt(index);
listKey.currentState!.removeItem(
index,
(context, animation) => SizeTransition(
axis: Axis.vertical,
sizeFactor: animation,
child: BoardListItem(
board: removedBoard,
index: index,
removeItemCallback: removeItemCallback(index),
),
),
duration: const Duration(milliseconds: 500));
setState(() {});
});
}
#override
Widget build(BuildContext context) {
return AnimatedList(
shrinkWrap: true,
physics: const ClampingScrollPhysics(),
key: listKey,
initialItemCount: boards.length,
itemBuilder: (context, index, animation) {
return SizeTransition(
axis: Axis.vertical,
sizeFactor: animation,
child: BoardListItem(
board: boards[index],
index: index,
removeItemCallback: removeItemCallback(index)));
},
);
}
}
class BoardListItem extends StatefulWidget {
const BoardListItem(
{Key? key,
required this.board,
required this.index,
required this.removeItemCallback})
: super(key: key);
final Board board;
final int index;
final void Function()? removeItemCallback;
#override
State<StatefulWidget> createState() => _BoardListItem();
}
class _BoardListItem extends State<BoardListItem> {
late final TextEditingController bigStakeController;
late final TextEditingController smallStakeController;
late final TextEditingController numberController;
#override
void initState() {
super.initState();
print('initing state');
bigStakeController =
TextEditingController(text: widget.board.bigStake.toString());
smallStakeController =
TextEditingController(text: widget.board.smallStake.toString());
numberController =
TextEditingController(text: widget.board.number.toString());
bigStakeController.addListener(() {
if (bigStakeController.text.isNotEmpty) {
widget.board.bigStake = int.parse(bigStakeController.text);
} else {
widget.board.bigStake = 0;
}
});
smallStakeController.addListener(() {
if (smallStakeController.text.isNotEmpty) {
widget.board.smallStake = int.parse(smallStakeController.text);
} else {
widget.board.smallStake = 0;
}
});
}
#override
void dispose() {
print('disposing these');
bigStakeController.dispose();
smallStakeController.dispose();
numberController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 5),
child: Container(
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
border: Border.all(color: Colors.grey, width: 1.5)),
child: Column(children: [
Container(
decoration: const BoxDecoration(
border: Border(
bottom: BorderSide(width: 1.5, color: Colors.grey))),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
IconButton(
onPressed: (() {
numberController.text = '1234';
}),
icon: const Icon(Icons.shuffle)),
Text(
'Board ${widget.index + 1}',
style: const TextStyle(fontWeight: FontWeight.w500),
),
IconButton(
onPressed: widget.removeItemCallback,
icon: const Icon(Icons.delete_outline))
],
),
),
Container(
margin: const EdgeInsets.only(top: 15),
decoration: const BoxDecoration(
border: Border(
bottom: BorderSide(width: 1.5, color: Colors.grey))),
child: PinCodeTextField(
controller: numberController,
autoDisposeControllers: false,
autoUnfocus: false,
length: 4,
showCursor: true,
enablePinAutofill: false,
keyboardType: TextInputType.number,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
textStyle: const TextStyle(
fontSize: 20, fontWeight: FontWeight.w500),
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[0-9]'))
],
animationType: AnimationType.scale,
//errorAnimationController: errorController,
appContext: context,
pinTheme: PinTheme(
shape: PinCodeFieldShape.box,
borderRadius: BorderRadius.circular(5),
fieldHeight: 50,
fieldWidth: 40,
selectedColor: const Color(0xFFB666D2),
inactiveColor: Colors.grey.shade400,
activeColor: const Color(0xFFB666D2)),
onChanged: (value) {
widget.board.number = value;
},
beforeTextPaste: (text) => false,
)),
IntrinsicHeight(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
SizedBox(
width: MediaQuery.of(context).size.width * 0.3,
child: Padding(
padding: const EdgeInsets.symmetric(
vertical: 5), //To manage vertical divider height
child: TextFormField(
controller: bigStakeController,
onTap: () {
if (widget.board.bigStake == 0) {
bigStakeController.clear();
}
},
onEditingComplete: () {
if (widget.board.bigStake == 0) {
bigStakeController.text = '0';
}
FocusManager.instance.primaryFocus?.unfocus();
},
enableInteractiveSelection: false,
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[0-9]'))
],
keyboardType: TextInputType.number,
decoration: const InputDecoration(
floatingLabelBehavior: FloatingLabelBehavior.always,
border: InputBorder.none,
isDense: true,
label: Text('Big'),
),
)),
),
const VerticalDivider(
thickness: 1.5,
color: Colors.grey,
),
SizedBox(
width: MediaQuery.of(context).size.width * 0.3,
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 5.0),
child: TextFormField(
controller: smallStakeController,
onTap: () {
if (widget.board.smallStake == 0) {
smallStakeController.clear();
}
},
onEditingComplete: () {
if (widget.board.smallStake == 0) {
smallStakeController.text = '0';
}
FocusManager.instance.primaryFocus?.unfocus();
},
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[0-9]'))
],
keyboardType: TextInputType.number,
enableInteractiveSelection: false,
decoration: const InputDecoration(
border: InputBorder.none,
isDense: true,
floatingLabelBehavior: FloatingLabelBehavior.always,
label: Text('Small'),
),
),
),
)
],
),
),
])),
);
}
}
When removing the first item, an unexpected behavior happens where the controller's text is sent to the second item. This does not happen when you remove the second item. (e.g Removing board 2).
Upon checking my data source for my second item, nothing was changed too.
Am I implementing TextEditingControllers into an AnimatedList wrongly? And if so, how do I properly implement it?
Please Help me
I want to know how to upload the first name, last name, job, date of birth and a picture of the user in Flutter Null Safety
this is my signup
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:newlivenullsaf/pages/login.dart';
class Signup extends StatefulWidget {
#override
State<Signup> createState() => _SignupState();
}
class _SignupState extends State<Signup> {
final _formkey = GlobalKey<FormState>();
var email = '';
var password = '';
var confirmPassword = '';
#override
void dispose() {
emailController.dispose();
passwordController.dispose();
confirmPasswordController.dispose();
super.dispose();
}
bool isLoading = false;
final nameController = TextEditingController();
final emailController = TextEditingController();
final passwordController = TextEditingController();
final confirmPasswordController = TextEditingController();
registeration() async {
if (password == confirmPassword) {
try {
UserCredential userCredential = await FirebaseAuth.instance
.createUserWithEmailAndPassword(email: email, password: password);
print(UserCredential);
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
backgroundColor: Colors.blueGrey,
content: Text(
'Registerd Successfully. Please Sign In ',
style: TextStyle(fontSize: 20.0),
),
),
);
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => const LoginPage(),
),
);
} on FirebaseAuthException catch (error) {
if (error.code == 'week-password') {
print('Password is too week');
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
backgroundColor: Colors.blueGrey,
content: Text(
'Password is too week ',
style: TextStyle(fontSize: 20.0, color: Colors.amberAccent),
),
),
);
} else if (error.code == 'email-already-in-use') {
print('Account is already exists');
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
backgroundColor: Colors.blueGrey,
content: Text(
'Account is already exists ',
style: TextStyle(fontSize: 20.0, color: Colors.amberAccent),
),
),
);
}
}
} else {
print('Password and Confirm Password does not match ');
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
backgroundColor: Colors.blueGrey,
content: Text(
'Password and Confirm Password does not match ',
style: TextStyle(fontSize: 20.0, color: Colors.amberAccent),
),
),
);
}
}
#override
Widget build(BuildContext context) {
final size = MediaQuery.of(context).size;
return Scaffold(
backgroundColor: Colors.white,
body: isLoading
? Center(
child: Container(
height: size.height / 20,
width: size.height / 20,
child: CircularProgressIndicator(),
),
)
: Form(
key: _formkey,
child: Padding(
padding: const EdgeInsets.symmetric(
vertical: 20.0, horizontal: 20.0),
child: ListView(
children: [
Padding(
padding: const EdgeInsets.all(30.0),
child: Image.asset('images/signup.png'),
),
Container(
margin: const EdgeInsets.symmetric(vertical: 10.0),
child: TextFormField(
autofocus: false,
decoration: const InputDecoration(
labelText: 'Name:',
labelStyle: TextStyle(fontSize: 20.0),
border: OutlineInputBorder(),
errorStyle: TextStyle(
color: Colors.black26, fontSize: 15.0),
),
controller: nameController,
validator: (value) {
if (value == null || value.isNotEmpty) {
return 'Please Enter Your Name';
}
if (value.length > 4) {
return (' Name(Max. 4 Character)');
}
return null;
}),
),
Container(
margin: const EdgeInsets.symmetric(vertical: 10.0),
child: TextFormField(
autofocus: false,
decoration: const InputDecoration(
labelText: 'Last Name:',
labelStyle: TextStyle(fontSize: 20.0),
border: OutlineInputBorder(),
errorStyle: TextStyle(
color: Colors.black26, fontSize: 15.0),
),
controller: nameController,
validator: (value) {
if (value == null || value.isNotEmpty) {
return 'Please Enter Your Last Name';
}
if (value.length > 4) {
return ('Last Name(Max. 4 Character)');
}
return null;
}),
),
Container(
margin: const EdgeInsets.symmetric(vertical: 10.0),
child: TextFormField(
autofocus: false,
decoration: const InputDecoration(
labelText: 'Email:',
labelStyle: TextStyle(fontSize: 20.0),
border: OutlineInputBorder(),
errorStyle:
TextStyle(color: Colors.black26, fontSize: 15.0),
),
controller: emailController,
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please Enter Email';
} else if (!value.contains('#')) {
return 'Please Enter Valid Email';
}
return null;
},
),
),
Container(
margin: const EdgeInsets.symmetric(vertical: 10.0),
child: TextFormField(
autofocus: false,
obscureText: true,
decoration: const InputDecoration(
labelText: ' Password',
labelStyle: TextStyle(fontSize: 20.0),
border: OutlineInputBorder(),
errorStyle:
TextStyle(color: Colors.black26, fontSize: 15.0),
),
controller: passwordController,
validator: (value) {
if (value == null ||
value.isEmpty ||
value.length < 6 ||
value.length > 14) {
return 'Please Enter Password';
}
return null;
},
),
),
Container(
margin: const EdgeInsets.symmetric(vertical: 10.0),
child: TextFormField(
autofocus: false,
obscureText: true,
decoration: const InputDecoration(
labelText: 'Confirm Password',
labelStyle: TextStyle(fontSize: 20.0),
border: OutlineInputBorder(),
errorStyle:
TextStyle(color: Colors.black26, fontSize: 15.0),
),
controller: confirmPasswordController,
validator: (value) {
if (value == null ||
value.isEmpty ||
value.length < 6 ||
value.length > 14) {
return 'Please Confirm Password';
}
return null;
},
),
),
const SizedBox(
height: 10.0,
),
Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () {
if (_formkey.currentState!.validate()) {
setState(() {
email = emailController.text;
password = passwordController.text;
confirmPassword =
confirmPasswordController.text;
});
registeration();
}
},
child: const Text(
'Signup ',
style: TextStyle(fontSize: 18.0),
),
),
],
),
),
Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text('Already Have An Account ?'),
TextButton(
onPressed: () {
Navigator.pushReplacement(
context,
PageRouteBuilder(
pageBuilder:
(context, animation1, animation2) =>
const LoginPage(),
transitionDuration:
const Duration(seconds: 0),
),
);
},
child: const Text('Login'),
),
],
),
),
],
),
),
),
);
}
}
this is my main
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'package:newlivenullsaf/pages/login.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
final Future<FirebaseApp> _initialization = Firebase.initializeApp();
#override
Widget build(BuildContext context) {
return FutureBuilder(
future: _initialization,
builder: (context, snapshot) {
if (snapshot.hasError) {
print('something wrong');
}
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(
child: CircularProgressIndicator(),
);
}
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter email & password',
theme: ThemeData(primarySwatch: Colors.blue),
home: const LoginPage(),
);
},
);
}
}
this is my login
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:newlivenullsaf/pages/forget_password.dart';
import 'package:newlivenullsaf/pages/signup.dart';
import 'package:newlivenullsaf/pages/user_main.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>();
var email = "";
var password = "";
final emailController = TextEditingController();
final passwordController = TextEditingController();
userLogin() async {
try {
await FirebaseAuth.instance
.signInWithEmailAndPassword(email: email, password: password);
Navigator.pushReplacement(
context, MaterialPageRoute(builder: (context) => const UserMain()));
} on FirebaseAuthException catch (error) {
if (error.code == ' user-not-found') {
print('No user found for that email ');
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
backgroundColor: Colors.blueGrey,
content: Text(
'No user found for that email',
style: TextStyle(
fontSize: 18.0,
color: Colors.amber,
),
),
),
);
} else if (error.code == 'wrong-password') {
print('wrong password provided by the user');
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
backgroundColor: Colors.blueGrey,
content: Text(
'wrong password provided by the user',
style: TextStyle(
fontSize: 18.0,
color: Colors.amber,
),
),
),
);
}
}
}
#override
void dispose() {
emailController.dispose();
passwordController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: Form(
key: _formKey,
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 40.0, horizontal: 20.0),
child: ListView(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Image.asset('images/login.jpg'),
),
Container(
margin: const EdgeInsets.symmetric(vertical: 10.0),
child: TextFormField(
autofocus: false,
decoration: const InputDecoration(
labelText: 'Email:',
labelStyle: TextStyle(fontSize: 20.0),
border: OutlineInputBorder(),
errorStyle:
TextStyle(color: Colors.black26, fontSize: 15.0),
),
controller: emailController,
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please Enter Email';
} else if (!value.contains('#')) {
return 'Please Enter Valid Email';
}
return null;
}),
),
Container(
margin: const EdgeInsets.symmetric(vertical: 10.0),
child: TextFormField(
autofocus: false,
obscureText: true,
decoration: const InputDecoration(
labelText: 'Password',
labelStyle: TextStyle(fontSize: 20.0),
border: OutlineInputBorder(),
errorStyle:
TextStyle(color: Colors.black26, fontSize: 15.0),
),
controller: passwordController,
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please Enter Password';
}
return null;
},
),
),
Container(
margin: const EdgeInsets.symmetric(vertical: 20.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () {
if (_formKey.currentState!.validate()) {
setState(() {
email = emailController.text;
password = passwordController.text;
});
userLogin();
}
},
child: const Text(
'Login',
style: TextStyle(fontSize: 18.0),
),
),
TextButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ForgotPass(),
),
);
},
child: const Text(
'Forget Password ?',
style: TextStyle(
fontSize: 12.0,
),
),
)
],
),
),
Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text('Do Not Have Account ?'),
TextButton(
onPressed: () {
Navigator.pushAndRemoveUntil(
context,
PageRouteBuilder(
pageBuilder: (context, a, b) => Signup(),
transitionDuration: const Duration(seconds: 0),
),
(route) => false);
},
child: const Text('Signup'),
),
],
),
),
],
),
),
),
);
}
}
Iused these packages
firebase_core: ^1.5.0
firebase_auth: ^3.0.2
I searched a lot and found a lot of codes and This code is the best I've found
please i need help quickly
I think you have to add (keep the auth like it is) cloud firestore and set a doc for each user contains his name , last name , job , profile pic etc...
so every user will have doc on cloud firestore and user on Auth
some sources :
to set the user in singUp page :
https://petercoding.com/firebase/2020/04/04/using-cloud-firestore-in-flutter/
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'm working on flutter project and came across a problem. the textfield supposed to take a value from controller which work perfectly but onChanged function wont work. However it is not working.i must retype value to show results .
how can i get result from onchanged when my textfield brings the value ?
code:
// search function that call api
class _SearchPageTState extends State<SearchPageT> {
GlobalState _store = GlobalState.instance;
List<dynamic> searchResults = [];
searchT(value) async {
SearchServicet.searchApiT(value).then((responseBody) {
List<dynamic> data = jsonDecode(responseBody);
setState(() {
data.forEach((value) {
searchResults.add(value);
});
});
});
}
#override
///////
//code textfield search onchanged
Widget build(BuildContext context) {
return MaterialApp(
localizationsDelegates: [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
debugShowCheckedModeBanner: false,
home: Scaffold(
appBar: AppBar(
centerTitle: true,
),
body: ListView(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(10.0),
child: TextField(
autofocus: true,
controller: TextEditingController()
..text = '${_store.get('num')}',
onChanged: (value) {
searchResults.clear();
searchCodeighniterT(value);
},
textAlign: TextAlign.center,
decoration: InputDecoration(
contentPadding: EdgeInsets.only(left: 25.0),
labelText: 'number',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(4.0),
),
suffixIcon: IconButton(
icon: Icon(Icons.search),
onPressed: null,
),
),
),
),
SizedBox(
height: 10.0,
),
ListView.builder(
physics: ScrollPhysics(),
shrinkWrap: true,
itemCount: searchResults.length,
itemBuilder: (BuildContext context, int index) {
return buildResultCard(context, searchResults[index]);
},
),
],
),
),
);
}
//here where shows the result
Widget buildResultCard(BuildContext context, data) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: <Widget>[
new Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("assets/bgwlgo.png"), fit: BoxFit.cover),
),
margin: EdgeInsets.all(5.0),
child: Column(
children: <Widget>[
new Card(
child: ListTile(
title: Text(
"DATE:",
),
subtitle: Text(
data['DATETIME'].toString(),
),
),
),
new Card(
child: ListTile(
title: Text(
"TRAITEMENT:",
),
subtitle: Text(
data['TRAITEMENT_DETAIL'].toString()
),
),
),
new Padding(
padding: EdgeInsets.all(9.0),
),
],
),
),
Divider(
color: Colors.black,
)
],
),
);
}
As discussed and understood in the comments, here are a couple of possible solutions for the issue.
If you are using a stateful Widget and need a controller for your TextFormField, you can use it to set the text on the TextFormField. Otherwise, you can just use the initialValue property:
class TextFieldIssue64061076 extends StatelessWidget {
final TextEditingController _textEditingController = TextEditingController();
#override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children:[
Text('Page 1'),
TextFormField(
controller: _textEditingController,
),
FlatButton(
child: Text('Submit'),
onPressed: () => Navigator.of(context).push(MaterialPageRoute(
builder: (context) {
return SecondPage64061076(text: _textEditingController.text);
}
)),
),
],
);
}
}
class SecondPage64061076 extends StatefulWidget {
final String text;
SecondPage64061076({
this.text
});
#override
_SecondPage64061076State createState() => _SecondPage64061076State();
}
class _SecondPage64061076State extends State<SecondPage64061076> {
final TextEditingController _textEditingController = TextEditingController();
#override
void initState() {
// You can either use a text controller to set the text on the text field
// or the initialValue below
if(widget.text != null && widget.text != ''){
_textEditingController.text = widget.text;
methodToCallOnChanged(widget.text);
}else{
_textEditingController.text = '';
}
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Page 2'),
TextFormField(
controller: _textEditingController,
onChanged: (value) => methodToCallOnChanged(value),
// As mentioned you could just use the initial value, it you don't need
// a Stateful Widget
// initialValue: widget.text ?? '',
),
]
),
);
}
void methodToCallOnChanged(data){
print('I was called onChange or when the view opened and there was data');
}
}
Widget build(BuildContext context) {
bool isRecording = false;
bool isShowSendButton = false;
/// make sure textcontroller and any variabloes or booleans are not defined
///in the build method
}
You can't be using the constructor of the TextEditingController and assign it to the controller.
The controller of the TextField only takes the variable assigned to the TextEditingController. Check the following code.
controller:theNameOfYourController
Expanded(
flex: 8,
child: Padding(
padding: const EdgeInsets.only(left: 8.0, right: 10),
child: TextFormField(
onChanged: (value){
messageFieldController.text=value;
},
//controller: messageFieldController,
minLines: 1,
maxLines: 2,
textCapitalization: TextCapitalization.sentences,
keyboardType: TextInputType.multiline,
decoration: InputDecoration(
prefixIcon: IconButton(
onPressed: () {},
icon: const Icon(Icons.add, color: Colors.blue),
),
suffixIcon: processing == true
? const CircularProgressIndicator()
: IconButton(
onPressed: () {
try {
/*for (int i = 0;
i < widget.selectedMembers.length;
i++) {
sendMessage(
widget.selectedMembers[i].number);
}*/
for (int i = 0;
i < widget.selectedGroups.length;
i++) {
if (widget.selectedGroups.isNotEmpty) {
sendMessageToGroup(
widget.selectedGroups[i].id,
widget.selectedGroups[i].groupName);
}
}
} catch (err) {
Fluttertoast.showToast(
msg: 'Unable to send Message');
setState(() {
processing = false;
});
}
},
icon:
const Icon(Icons.send, color: Colors.blue),
),
border: const OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(50),
),
),
),
),
),
)