When I run my program to submit this form, the validator runs and returns with correct error checking however I can not come up with a method to get the onSaved method of the TextFormFields to work. I do not however receive any errors when running the code and the dropdown buttons work and upload to firebase properly. I currently have name set to a print to the logcat for debugging, but it never gets called.
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:connectuproject/authentication.dart';
class player_reg extends StatefulWidget {
player_reg(this.auth);
final BaseAuth auth;
#override
State<StatefulWidget> createState() => new PlayerRegState();
}
class PlayerRegState extends State<player_reg> {
final _formKey = new GlobalKey<FormState>();
String _name = "";
String _age = "";
String _grad = "";
String _highschool = "";
String _city = "";
String _state = "";
String _heightFeet = "";
String _heightInch = "";
String _weight = "";
String _hand = "Right";
String _number = "";
String _email = "";
String _errorMessage = "";
String _position = "Attack";
String _club = "";
bool _isLoading = false;
bool validateAndSave() {
if (_formKey.currentState.validate()) {
_formKey.currentState.save();
return true;
}
return false;
}
void validateAndSubmit() async {
setState(() {
_errorMessage = "";
_isLoading = true;
});
print("Auth: " + widget.auth.getUserId());
if (validateAndSave()) {
try {
String _uid = widget.auth.getUserId();
print("_uid: " + _uid + " Name: " + _name);
final databaseReference = Firestore.instance;
await databaseReference.collection("users").document(_uid).setData({
'name': _name,
'age': _age,
'grade': _grad,
'highschool': _highschool,
'state': _state,
'city': _city,
'heightFeet': _heightFeet,
'heightInch': _heightInch,
'weight': _weight,
'hand': _hand,
'position': _position,
'club': _club,
});
}
catch(e){
print(e.message);
}
}
setState(() {
_isLoading = false;
});
}
#override
void initState() {
_errorMessage = "";
_isLoading = false;
super.initState();
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('Flutter login demo'),
),
body: Stack(
children: <Widget>[
_showForm(),
_showCircularProgress(),
],
));
}
Widget _showCircularProgress() {
if (_isLoading) {
return Center(child: CircularProgressIndicator());
}
return Container(
height: 0.0,
width: 0.0,
);
}
Widget _showForm() {
return new Container(
padding: EdgeInsets.all(16.0),
child: new Form(
key: _formKey,
child: new ListView(
shrinkWrap: true,
children: <Widget>[
showInstruct(),
showPerson(),
showNameInput(),
showAgeInput(),
showGradInput(),
showHighschoolInput(),
showStateInput(),
showCityInput(),
showPhysical(),
showHeightFeetInput(),
showHeightInchesInput(),
showWeightInput(),
showHandiness(),
showHandinessInput(),
showContact(),
showNumberInput(),
showEmailInput(),
showLacrosse(),
showPosition(),
showPositionInput(),
showClubInput(),
showSubmitButton(),
],
),
),
);
}
Widget showInstruct() {
return new Text(
"Please complete the following ",
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.black,
fontFamily: 'Raleway',
fontSize: 30.0,
fontWeight: FontWeight.bold,
),
);
}
Widget showPerson() {
return new Padding(
padding: const EdgeInsets.fromLTRB(0.0, 50.0, 0.0, 0.0),
child: new Text(
"Personal info: ",
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.black,
fontFamily: 'Raleway',
fontSize: 30.0,
),
));
}
Widget showNameInput() {
return Padding(
padding: const EdgeInsets.fromLTRB(0.0, 25.0, 0.0, 0.0),
child: new TextFormField(
maxLines: 1,
autofocus: false,
decoration: new InputDecoration(
hintText: 'Name',
),
validator: (value) => value.isEmpty ? 'Name can\'t be empty' : null,
onSaved: (String value) => print("saving the name value of " + value),
),
);
}
Widget showAgeInput() {
return Padding(
padding: const EdgeInsets.fromLTRB(0.0, 25.0, 0.0, 0.0),
child: new TextFormField(
maxLines: 1,
maxLength: 2,
autofocus: false,
keyboardType: TextInputType.number,
decoration: new InputDecoration(
hintText: 'Age',
),
validator: (value) => value.isEmpty ? 'Age can\'t be empty' : null,
onSaved: (String value) => _age = value.trim(),
),
);
}
Widget showGradInput() {
return Padding(
padding: const EdgeInsets.fromLTRB(0.0, 25.0, 0.0, 0.0),
child: new TextFormField(
maxLines: 1,
maxLength: 4,
autofocus: false,
keyboardType: TextInputType.number,
decoration: new InputDecoration(
hintText: 'Graduation year',
),
validator: (value) =>
value.isEmpty ? 'Graduation year can\'t be empty' : null,
onSaved: (String value) => _grad = value.trim(),
),
);
}
Widget showHighschoolInput() {
return Padding(
padding: const EdgeInsets.fromLTRB(0.0, 25.0, 0.0, 0.0),
child: new TextFormField(
maxLines: 1,
autofocus: false,
decoration: new InputDecoration(
hintText: 'Highschool',
),
validator: (value) =>
value.isEmpty ? 'Highschool can\'t be empty' : null,
onSaved: (String value) => _highschool = value.trim(),
),
);
}
Widget showStateInput() {
return Padding(
padding: const EdgeInsets.fromLTRB(0.0, 25.0, 0.0, 0.0),
child: new TextFormField(
maxLines: 1,
autofocus: false,
decoration: new InputDecoration(
hintText: 'State',
),
validator: (value) => value.isEmpty ? 'State can\'t be empty' : null,
onSaved: (String value) => _state = value.trim(),
),
);
}
Widget showCityInput() {
return Padding(
padding: const EdgeInsets.fromLTRB(0.0, 25.0, 0.0, 50.0),
child: new TextFormField(
maxLines: 1,
autofocus: false,
decoration: new InputDecoration(
hintText: 'City',
),
validator: (value) => value.isEmpty ? 'State can\'t be empty' : null,
onSaved: (String value) => _city = value.trim(),
),
);
}
Widget showPhysical() {
return new Text(
"Physical info: ",
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.black,
fontFamily: 'Raleway',
fontSize: 30.0,
),
);
}
Widget showHeightFeetInput() {
return Padding(
padding: const EdgeInsets.fromLTRB(0.0, 25.0, 0.0, 0.0),
child: new TextFormField(
maxLines: 1,
maxLength: 1,
autofocus: false,
keyboardType: TextInputType.number,
decoration: new InputDecoration(
hintText: 'Height(feet)',
),
validator: (value) => value.isEmpty ? 'Height can\'t be empty' : null,
onSaved: (String value) => _heightFeet = value.trim(),
),
);
}
Widget showHeightInchesInput() {
return Padding(
padding: const EdgeInsets.fromLTRB(0.0, 25.0, 0.0, 0.0),
child: new TextFormField(
maxLines: 1,
maxLength: 2,
autofocus: false,
keyboardType: TextInputType.number,
decoration: new InputDecoration(
hintText: 'Height(inches)',
),
validator: (value) => value.isEmpty ? 'Height can\'t be empty' : null,
onSaved: (String value) => _heightInch = value.trim(),
),
);
}
Widget showWeightInput() {
return Padding(
padding: const EdgeInsets.fromLTRB(0.0, 25.0, 0.0, 0.0),
child: new TextFormField(
maxLines: 1,
maxLength: 3,
autofocus: false,
keyboardType: TextInputType.number,
decoration: new InputDecoration(
hintText: 'weight(lbs)',
),
validator: (value) => value.isEmpty ? 'Weight can\'t be empty' : null,
onSaved: (String value) => _weight = value.trim(),
),
);
}
Widget showHandiness() {
return new Padding(
padding: const EdgeInsets.fromLTRB(0.0, 25.0, 0.0, 0.0),
child: Text(
"Handiness:",
style: TextStyle(fontSize: 20),
),
);
}
Widget showHandinessInput() {
return Padding(
padding: const EdgeInsets.fromLTRB(0.0, 0.0, 0.0, 0.0),
child: Container(
width: double.infinity,
child: new DropdownButton<String>(
isExpanded: true,
value: _hand,
elevation: 16,
underline: Container(
height: 2,
),
onChanged: (String newValue) {
setState(() {
_hand = newValue;
});
},
items: <String>['Right','Left']
.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
)),
);
}
Widget showContact() {
return new Text(
"Contact info: ",
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.black,
fontFamily: 'Raleway',
fontSize: 30.0,
),
);
}
Widget showNumberInput() {
return Padding(
padding: const EdgeInsets.fromLTRB(0.0, 25.0, 0.0, 0.0),
child: new TextFormField(
maxLines: 1,
autofocus: false,
keyboardType: TextInputType.phone,
decoration: new InputDecoration(
hintText: 'Phone Number',
),
validator: (value) => value.isEmpty ? 'Number can\'t be empty' : null,
onSaved: (String value) => _number = value.trim(),
),
);
}
Widget showEmailInput() {
return Padding(
padding: const EdgeInsets.fromLTRB(0.0, 25.0, 0.0, 50.0),
child: new TextFormField(
maxLines: 1,
autofocus: false,
keyboardType: TextInputType.emailAddress,
decoration: new InputDecoration(
hintText: 'Email',
),
validator: (value) => value.isEmpty ? 'Not a valid Email' : null,
onSaved: (String value) => _email = value.trim(),
),
);
}
Widget showLacrosse() {
return new Text(
"Lacrosse info: ",
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.black,
fontFamily: 'Raleway',
fontSize: 30.0,
),
);
}
Widget showPosition() {
return new Padding(
padding: const EdgeInsets.fromLTRB(0.0, 25.0, 0.0, 0.0),
child: Text(
"Position:",
style: TextStyle(fontSize: 20),
));
}
Widget showPositionInput() {
return Padding(
padding: const EdgeInsets.fromLTRB(0.0, 0.0, 0.0, 0.0),
child: Container(
width: double.infinity,
child: new DropdownButton<String>(
isExpanded: true,
value: _position,
elevation: 16,
underline: Container(
height: 2,
),
onChanged: (String newValue) {
setState(() {
_position = newValue;
});
},
items: <String>[
'Attack',
'Defense',
'Face-off',
'Goalie',
'Long Stick Midfield',
'Midfield'
].map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
)),
);
}
Widget showClubInput() {
return Padding(
padding: const EdgeInsets.fromLTRB(0.0, 25.0, 0.0, 50.0),
child: new TextFormField(
maxLines: 1,
autofocus: false,
decoration: new InputDecoration(
hintText: 'Club Team',
),
onSaved: (String value) => _club = value.trim(),
),
);
}
Widget showSubmitButton() {
return new Padding(
padding: EdgeInsets.fromLTRB(0.0, 45.0, 0.0, 25.0),
child: SizedBox(
height: 40.0,
child: new RaisedButton(
elevation: 5.0,
shape: new RoundedRectangleBorder(
borderRadius: new BorderRadius.circular(30.0)),
color: Colors.blue,
child: new Text("Submit"),
onPressed: validateAndSubmit,
),
));
}
}
enter code here
After a few days of hard effort I realized the form fields were clearing when I scrolled down the screen. The solution was to wrap the entire field in a SingleChildScrollView and replace my list view with a column.
Related
This is a part of a project regarding feedback forms.
I already manage to create the validation form properly thanks to the answers here in StackOverflow developers.
But the problem is creating this regular expression which seems to not work on the validation form. I found in flutter docs the Iterable but I do not know how can I implement it on the dart page.
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
class SimpleDialog extends StatelessWidget {
// ignore: prefer_typing_uninitialized_variables
final title;
const SimpleDialog(this.title, {super.key});
#override
Widget build(BuildContext context) {
return AlertDialog(
title: const Text('Alert'),
content: Text(title),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: const Text('OK'))
],
);
}
}
class FeedbackPage extends StatefulWidget {
const FeedbackPage({super.key});
#override
State<FeedbackPage> createState() => _FeedbackPageState();
}
class _FeedbackPageState extends State<FeedbackPage> {
final nameOfuser = TextEditingController();
final emailOfuser = TextEditingController();
final messageOfuser = TextEditingController();
final _formKey = GlobalKey<FormState>();
List<bool> isTypeSelected = [false, false, false, true, true];
#override
Widget build(BuildContext context) {
return Scaffold(
// AppBar para sa taas ng design
appBar: AppBar(
centerTitle: true,
title: const Text(
"PicLeaf",
style: TextStyle(
color: Color.fromRGBO(102, 204, 102, 1.0),
fontWeight: FontWeight.bold),
),
backgroundColor: Colors.white,
shadowColor: const Color.fromARGB(255, 95, 94, 94),
),
//body of the application
backgroundColor: const Color(0xffeeeeee),
body: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
const SizedBox(
height: 20,
),
const Text(
"Feedback",
style: TextStyle(
fontSize: 30.0,
fontFamily: 'RobotoBold',
fontWeight: FontWeight.bold,
color: Color.fromRGBO(102, 204, 102, 1.0)),
),
const Text(
"Give us your feedback!",
style: TextStyle(
fontSize: 18.0,
fontFamily: 'RobotoMedium',
),
),
const SizedBox(
height: 20,
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 32.0),
child: Form(
key: _formKey,
child: Column(
children: <Widget>[
const SizedBox(height: 16.0),
TextFormField(
controller: nameOfuser,
decoration: const InputDecoration(
filled: true,
fillColor: Colors.white,
hintText: "Name",
border: OutlineInputBorder(),
),
validator: (nameOfuser) {
if (nameOfuser == null || nameOfuser.isEmpty) {
return 'Please enter your Name';
}
return null;
},
),
const SizedBox(height: 8.0),
TextFormField(
controller: emailOfuser,
decoration: const InputDecoration(
filled: true,
fillColor: Colors.white,
hintText: "Email",
border: OutlineInputBorder(),
),
validator: (emailOfuser) {
if (emailOfuser == null || emailOfuser.isEmpty) {
String emailOfuser1 = emailOfuser.toString();
String pattern = r'\w+#\w+\.\w+';
if (RegExp(pattern).hasMatch(emailOfuser1)) {
return 'Please enter your Email Properly';
} else {
return 'Please enter your Email';
}
}
return null;
},
),
const SizedBox(height: 8.0),
TextFormField(
controller: messageOfuser,
maxLines: 6,
decoration: const InputDecoration(
filled: true,
fillColor: Colors.white,
hintText: "Message",
border: OutlineInputBorder(),
),
validator: (messageOfuser) {
if (messageOfuser == null || messageOfuser.isEmpty) {
return 'Please enter your Message';
}
return null;
},
),
const SizedBox(height: 8.0),
MaterialButton(
height: 50.0,
minWidth: double.infinity,
color: const Color.fromRGBO(102, 204, 102, 1.0),
onPressed: () {
if (_formKey.currentState!.validate()) {
showDialog(
context: context,
builder: (BuildContext context) {
return const SimpleDialog(
'Feedback Submitted');
});
Map<String, dynamic> data = {
"Name": nameOfuser.text,
"Email": emailOfuser.text,
"Message": messageOfuser.text,
"Time": FieldValue.serverTimestamp(),
};
setState(() {
nameOfuser.clear();
emailOfuser.clear();
messageOfuser.clear();
});
FirebaseFirestore.instance
.collection("FeedbackMessages")
.add(data);
}
},
child: const Text(
"SUBMIT",
style: TextStyle(
fontFamily: 'RobotoBold',
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
),
const SizedBox(
height: 10,
),
Container(
padding: const EdgeInsets.fromLTRB(20, 20, 20, 10),
child: const Text(
'Contact Us!',
style: TextStyle(
fontSize: 30,
fontFamily: 'RobotoBold',
color: Color.fromRGBO(102, 204, 102, 1.0)),
textAlign: TextAlign.center,
),
),
Column(
children: <Widget>[
Container(
padding: const EdgeInsets.fromLTRB(20, 0, 20, 0),
margin: const EdgeInsets.symmetric(horizontal: 0),
child: TextButton.icon(
// <-- TextButton
onPressed: () {},
icon: const Icon(
Icons.facebook,
color: Colors.black,
size: 35.0,
),
label: const Text(
'facebook.com/picleaf',
style: TextStyle(fontFamily: 'RobotoMedium'),
),
style: TextButton.styleFrom(
foregroundColor: Colors.black,
),
),
),
Container(
padding: const EdgeInsets.fromLTRB(20, 0, 20, 10),
margin: const EdgeInsets.symmetric(horizontal: 0),
child: TextButton.icon(
// <-- TextButton
onPressed: () {},
icon: const Icon(
Icons.email,
color: Colors.black,
size: 35.0,
),
label: const Text(
'picleaf#gmail.com',
style: TextStyle(fontFamily: 'RobotoMedium'),
),
style: TextButton.styleFrom(
foregroundColor: Colors.black,
),
)),
],
)
],
),
),
),
],
),
));
}
}
You can use this validator:
validator: (emailOfuser) {
if (emailOfuser == null || emailOfuser.isEmpty) {
return 'Please enter your Email';
} else if (emailOfuser.isNotEmpty) {
String emailOfuser1 = emailOfuser.toString();
String pattern = r'\w+#\w+\.\w+';
if (RegExp(pattern).hasMatch(emailOfuser1) == false) {
return 'Please enter your Email Properly';
}
}
return null;
},
try to implement like this:
import 'package:flutter/material.dart';
class EmailValidationForm extends StatefulWidget {
const EmailValidationForm({Key? key}) : super(key: key);
#override
State<EmailValidationForm> createState() => _EmailValidationFormState();
}
class _EmailValidationFormState extends State<EmailValidationForm> {
final GlobalKey<FormState> formKey = GlobalKey<FormState>();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Email Validation'),
),
body: Form(
key: formKey,
child: Column(
children: [
TextFormField(
autofocus: false,
maxLength: 300,
keyboardType: TextInputType.emailAddress,
autocorrect: false,
validator: (email) {
if (email!.isEmpty) {
return 'required field';
} else if (email.trim().contains(' ')) {
return 'contain space';
} else if (!emailValid(email)) {
return 'invalid email';
}
return null;
},
onSaved: (email) {
return debugPrint(email);
},
),
ElevatedButton(
onPressed: () {
if (formKey.currentState!.validate()) {
formKey.currentState!.save();
}
},
child: const Text('Validate')),
],
),
),
);
}
}
bool emailValid(String email) {
final RegExp regex = RegExp(
r"^(([^<>()[\]\\.,;:\s#\']+(\.[^<>()[\]\\.,;:\s#\']+)*)|(\'.+\'))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$");
return regex.hasMatch(email.trim());
}
I am new to flutter and i am working on a result processing and record keeping system in the result processing part i have a form that takes in some details about the students like session, level, course code(It's for a university). now i have a collection in firebase of the levels and sessions in the department i am using for a case study and would like to check that the lecturer input corresponds or matches what is in the database.I am using a textformfield but i don't know how to validate the input with what is in firebase database. This is my code for the form. Thanks in advance for the help
class ScoreSheetPage extends StatefulWidget {
#override
State<ScoreSheetPage> createState() => _ScoreSheetPageState();
}
class _ScoreSheetPageState extends State<ScoreSheetPage> {
final formKey = GlobalKey<FormState>();
TextEditingController currentSession = TextEditingController();
TextEditingController currentLevelYear = TextEditingController();
TextEditingController matriculationNumber = TextEditingController();
TextEditingController currentSemester = TextEditingController();
TextEditingController courseCode = TextEditingController();
TextEditingController studentMarks1 = TextEditingController();
TextEditingController studentMarks2 = TextEditingController();
TextEditingController studentMarks3 = TextEditingController();
TextEditingController studentMarks4 = TextEditingController();
#override
Widget build(BuildContext context) {
final double height = MediaQuery.of(context).size.height;
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
return Scaffold(
backgroundColor: Colors.white,
body: SafeArea(
child: SingleChildScrollView(
child: Column(
children: [
Stack(
children: [
Container(
height: 230,
decoration: BoxDecoration(color: Color(0xFF363f93)),
),
SizedBox(
height: 100,
),
Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
alignment: Alignment.bottomCenter,
child: Text(
"RHEMA UNIVERSITY RESULT CALCULATION SYSTEM",
textAlign: TextAlign.center,
style: kHeading,
),
),
Text(
"Welcome",
textAlign: TextAlign.center,
style: kHeading,
),
],
),
)
],
),
Container(
alignment: Alignment.topLeft,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Form(
key: formKey,
child: Column(
children: [
Text(
"Please fill in the required information",
style: TextStyle(
color: Color(0xFF363f93),
fontSize: 30,
fontWeight: FontWeight.bold,
),
textAlign: TextAlign.start,
),
SizedBox(
height: height * 0.04,
),
TextFormField(
controller: currentSession,
decoration: InputDecoration(
labelText:
"Enter current session, use format(1234-1234)"),
validator: (value) {
if (value!.isEmpty ||
!RegExp(r'^([0-9]{4}[-][0-9]{4})+$')
.hasMatch(value)) {
return "Enter correct session number";
} else {
return null;
}
},
),
SizedBox(
height: height * 0.04,
),
TextFormField(
controller: currentLevelYear,
decoration: InputDecoration(
labelText: "Enter Current Level/year"),
validator: (value) {
if (value!.isEmpty ||
!RegExp(r'^([0-9]{3})+$').hasMatch(value)) {
return "Enter correct level and year";
} else {
return null;
}
},
),
SizedBox(
height: height * 0.04,
),
TextFormField(
controller: matriculationNumber,
decoration: InputDecoration(
labelText:
"Enter student's matriculation number, use format(RU-CSC-19-202)"),
validator: (value) {
if (value!.isEmpty ||
!RegExp(r'^[A-Z]{2}[-][A-Z]{3}[-][0-9]{2}[-][0-9]{3}')
.hasMatch(value)) {
return "Enter correct Matriculation Number";
} else {
return null;
}
},
),
SizedBox(
height: height * 0.04,
),
TextFormField(
controller: currentSemester,
decoration: InputDecoration(
labelText: "Enter current semester"),
validator: (value) {
if (value!.isEmpty ||
!RegExp(r'^[a-z,A-Z]+$').hasMatch(value)) {
return "Enter correct name";
} else {
return null;
}
},
),
SizedBox(
height: height * 0.04,
),
TextFormField(
controller: studentMarks1,
decoration: InputDecoration(
labelText: "Enter score for attendance"),
validator: (value) {
if (value!.isEmpty ||
!RegExp(r'^[0-9]+$').hasMatch(value)) {
return "Enter correct score";
} else {
return null;
}
},
),
SizedBox(
height: height * 0.05,
),
TextFormField(
controller: studentMarks2,
decoration: InputDecoration(
labelText: "Enter score for assignment"),
validator: (value) {
if (value!.isEmpty ||
!RegExp(r'^[0-9]+$').hasMatch(value)) {
return "Enter correct score";
} else {
return null;
}
},
),
SizedBox(
height: height * 0.05,
),
TextFormField(
controller: studentMarks3,
decoration: InputDecoration(
labelText: "Enter score for test"),
validator: (value) {
if (value!.isEmpty ||
!RegExp(r'^[0-9]+$').hasMatch(value)) {
return "Enter correct score";
} else {
return null;
}
},
),
SizedBox(
height: height * 0.05,
),
TextFormField(
controller: studentMarks4,
decoration: InputDecoration(
labelText: "Enter Score for exams"),
validator: (value) {
if (value!.isEmpty ||
!RegExp(r'^[0-9]+$').hasMatch(value)) {
return "Enter correct score";
} else {
return null;
}
},
),
SizedBox(
height: height * 0.05,
),
GestureDetector(
child: Container(
alignment: Alignment.center,
width: 500,
child: SizedBox(
height: 50,
width: double.infinity,
child: ElevatedButton(
style: ButtonStyle(
foregroundColor:
MaterialStateProperty.all<Color>(
Colors.black),
backgroundColor:
MaterialStateProperty.all(
Colors.black),
shape: MaterialStateProperty.all<
RoundedRectangleBorder>(
RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(
1000))),
),
child: Text("Submit", style: kHeading),
onPressed: () {
if (formKey.currentState!.validate()) {
var finalScore = int.parse(
studentMarks2.text) +
int.parse(studentMarks3.text) +
int.parse(studentMarks4.text);
Map<String, dynamic> data = {
"Attendance": studentMarks1.text,
"Assignment": studentMarks2.text,
"Test Score": studentMarks3.text,
"Examination Score":
studentMarks4.text,
"final score": finalScore
};
final docUser = FirebaseFirestore
.instance
.collection("Exam Scores")
.doc(
"${currentLevelYear.text} Level")
.collection(
matriculationNumber.text)
.doc(
"${currentSemester.text} semester")
.collection(courseCode.text)
.doc("Scores");
docUser.set(data);
}
}),
)),
),
SizedBox(
height: 15,
),
TextButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Homepage()));
},
child: Text(
"Go back to home page",
style: TextStyle(
fontSize: 25,
fontWeight: FontWeight.bold,
),
)),
],
),
),
)),
],
),
),
),
);
}
}
Textformfield will work for you. You just need to check the data type required for the firebase and you can also add a validator in the Textformfield and pass pass regex to it. Textformfield will valid the input data.
Warning: Ignoring header X-Firebase-Locale because its value was null.
I'm getting this warning while signing up a user in firebase. When i signup in my app it doesn't get added into firebase?(I'm working on flutter in VS Code). Code for my Signup Page is being written below:
class Signup extends StatefulWidget {
Signup ({ Key? key }) : super(key: key);
#override
_SignupState createState() => _SignupState();
}
class _SignupState extends State<Signup> {
final _formKey = GlobalKey<FormState>();
var email = " ";
var password = " ";
var confirmPassword = " ";
final emailController = TextEditingController();
final passwordController = TextEditingController();
final confirmPasswordController = TextEditingController();
#override
void dispose()
{
emailController.dispose();
passwordController.dispose();
confirmPasswordController.dispose();
super.dispose();
}
registration() async{
if(password == confirmPassword)
{
try{
await FirebaseAuth.instance.createUserWithEmailAndPassword(email: email, password: password);
}catch(e){}
}
else{
print("Password doesn't match");
}
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('User Signup'),
),
body : Form(
key: _formKey,
child: Padding(
padding: EdgeInsets.symmetric(vertical: 20, horizontal: 30),
child: ListView(
children: [
Container(
margin: EdgeInsets.symmetric(vertical: 10.0),
child: TextFormField(
autofocus: false,
decoration: InputDecoration(
labelText: 'Email: ',
labelStyle: TextStyle(fontSize: 20.0),
border: OutlineInputBorder(),
errorStyle:
TextStyle(color: Colors.redAccent,
fontSize: 15),
),
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: EdgeInsets.symmetric(vertical: 10.0),
child: TextFormField(
autofocus: false,
obscureText: true,
decoration: InputDecoration(
labelText: 'Password: ',
labelStyle: TextStyle(fontSize: 20.0),
border: OutlineInputBorder(),
errorStyle:
TextStyle(color: Colors.redAccent,
fontSize: 15),
),
controller: passwordController,
validator: (value)
{
if(value==null || value.isEmpty)
{
return 'Please Enter Password';
}
return null;
},
)
),
Container(
margin: EdgeInsets.symmetric(vertical: 10.0),
child: TextFormField(
autofocus: false,
obscureText: true,
decoration: InputDecoration(
labelText: 'Confirm Password: ',
labelStyle: TextStyle(fontSize: 20.0),
border: OutlineInputBorder(),
errorStyle:
TextStyle(color: Colors.redAccent,
fontSize: 15),
),
controller: confirmPasswordController,
validator: (value)
{
if(value==null || value.isEmpty)
{
return 'Please Enter Password';
}
return null;
},
)
),
Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () {
if(_formKey.currentState!.validate())
{
setState(() {
email = emailController.text;
password =passwordController.text;
confirmPassword = confirmPasswordController.text;
});
}
registration();
},
child: Text(
'Sign Up',
style: TextStyle(color: Colors.white, fontSize: 20),
)
)
],
),
),
Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children:[
Text("Already have an Account? "),
TextButton(
onPressed: ()=>{
Navigator.pushReplacement(
context,
PageRouteBuilder(
pageBuilder:
(context, animation1, animation2)
=>LoginPage(),
transitionDuration: Duration(seconds:0),
)
),
},
child: Text('Login')
)
]
)
)
],
)
)
)
);
}
}
I'm expecting to get a user added in firebase after signing up through my app.
I have three radio buttons so that the user can select their gender. However, only the male radio button is getting highlighted. Even though my console prints other radio buttons when selected, they don't get highlighted on screen. I don't know what to do about it so any help will be really appreciated!
import 'package:flutter/material.dart';
import 'package:vibing/User_Login.dart';
import 'package:vibing/register_user.dart';
import 'package:vibing/register_user.dart';
class UserDetails extends StatefulWidget {
#override
_UserDetailsState createState() => _UserDetailsState();
}
enum Gender{
Male, Female, Others
}
class _UserDetailsState extends State<UserDetails> {
#override
Widget build(BuildContext context) {
final formkey = GlobalKey<FormState>();
String user_name;
String user_age;
int group_value = -1;
Gender _gender = Gender.Male;
final _userName = Container(
padding: EdgeInsets.only(left: 10, right: 10),
child: TextFormField(
autofocus: false,
keyboardType: TextInputType.text,
validator: (value) {
if(value.isEmpty)
{
return 'Field cannot be empty';
}
return null;
},
onSaved: (value)=> user_name = value,
decoration: InputDecoration(
hintText: 'Enter Name',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10)
),
),
),
);
final _userAge = Container(
padding: EdgeInsets.only(left: 10, right: 10),
child: TextFormField(
keyboardType: TextInputType.number,
autofocus: false,
validator: (value) {
if(value.isEmpty)
{
return 'Field cannot be empty';
}
return null;
},
onSaved: (value)=> user_age = value,
decoration: InputDecoration(
hintText: 'Enter Age',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10)
),
),
),
);
final _male = Radio(
value: Gender.Male,
activeColor: Colors.black,
groupValue: _gender,
onChanged: (Gender value){
setState(() {
print(value);
_gender = value;
});
},
);
final _female = Radio(
activeColor: Colors.black,
value: Gender.Female,
groupValue: _gender,
onChanged: (Gender value){
setState(() {
print(value);
_gender = value;
});
},
);
final _others = Radio(
activeColor: Colors.black,
value: Gender.Others,
groupValue: _gender,
onChanged: (Gender value){
setState(() {
print(value);
_gender = value;
});
},
);
return Scaffold(
backgroundColor: Colors.yellow,
body: Container(
key: formkey,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text("Register",
style: TextStyle(fontSize: 64.0, fontWeight: FontWeight.bold),),
SizedBox(height: 50,),
_userName,
SizedBox(height: 20,),
_userAge,
SizedBox(height: 30,),
Row(
crossAxisAlignment: CrossAxisAlignment.center ,
children: <Widget>[
Text(" Gender: ", style: TextStyle(fontSize: 20.0),),
_male,
Text("Male"),
_female,
Text("Female"),
_others,
Text("Others"),
],
),
Row(
crossAxisAlignment: CrossAxisAlignment.center ,
children: <Widget>[
FloatingActionButton.extended(
heroTag: "next_button",
backgroundColor: Colors.yellow,
foregroundColor: Colors.black,
onPressed: ()=> Navigator.push(context, MaterialPageRoute(builder: (context)=>UserReg())),
label: Text("Next", style: TextStyle(fontWeight: FontWeight.bold),)
),
SizedBox(width: 230,),
FloatingActionButton.extended(
heroTag: "prev_button",
backgroundColor: Colors.yellow,
foregroundColor: Colors.black,
onPressed: ()=> Navigator.push(context, MaterialPageRoute(builder: (context)=>UserLogin())),
label: Text("Prev", style: TextStyle(fontWeight: FontWeight.bold),)
),
],
),
],
),
),
);
}
}
It doesn't work because you declare state inside the build function. Move it out :
class _UserDetailsState extends State<UserDetails> {
String user_name;
String user_age;
int group_value = -1;
Gender _gender = Gender.Male;
By the way, you can generate widgets for each enum value :
children: <Widget>[
for(var gender in Gender.values)
Radio(
value: gender,
activeColor: Colors.black,
groupValue: _gender,
onChanged: (Gender value){
setState(() {
print(value);
_gender = value;
});
},
);
]
Make sure your minimum SDK version is 2.6.0 or above in the pubspec.yaml
I wanted to know as to how can I submit the form which will print the user data from a previous page as well as the current page it is in? This will help me further when I am trying to update user data on firestore. I couldn't find a solution hence I would really appreciate whatever help I can get! :)
edit:
For anyone who didn't get what I was trying to say
I have the textfields of First Name, Last name and age in one page for which the user will press on the next button when done entering. In the final registration page which consists of email and password textfields contains the Register button which will register the user. I want to press Register on the final registration page which will print the data entered in the previous page as well as the current page. I wanted to know how can I achieve that so that later on I can update the user data to firestore
previous page
class UserDetails extends StatefulWidget {
#override
_UserDetailsState createState() => _UserDetailsState();
}
enum Gender{
Male, Female, Others
}
class _UserDetailsState extends State<UserDetails> {
String userFirstName;
String userLastName;
String user_age;
int group_value = -1;
Gender _gender = Gender.Male;
final formkeyDetails = GlobalKey<FormState>();
#override
Widget build(BuildContext context) {
//final _userProvider = Provider.of<UserProvider>(context);
final _firstName = Container(
padding: EdgeInsets.only(left: 10, right: 10),
child: TextFormField(
autofocus: false,
keyboardType: TextInputType.text,
/*onChanged: (value){
_userProvider.changeFirstName(value);
},
*/
validator: (value) {
if(value.isEmpty)
{
return 'Field cannot be empty';
}
return null;
},
onSaved: (value)=> userFirstName = value,
decoration: InputDecoration(
hintText: 'Enter First Name',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10)
),
),
),
);
final _lastName = Container(
padding: EdgeInsets.only(left: 10, right: 10),
child: TextFormField(
autofocus: false,
keyboardType: TextInputType.text,
/* onChanged: (value){
_userProvider.changeLastName(value);
}
,
*/
validator: (value) {
if(value.isEmpty)
{
return 'Field cannot be empty';
}
return null;
},
onSaved: (value)=> userLastName = value,
decoration: InputDecoration(
hintText: 'Enter Last Name',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10)
),
),
),
);
final _userAge = Container(
padding: EdgeInsets.only(left: 10, right: 10),
child: TextFormField(
keyboardType: TextInputType.number,
autofocus: false,
/* onChanged: (value){
_userProvider.changeAge(value);
},
*/
validator: (value) {
if(value.isEmpty)
{
return 'Field cannot be empty';
}
return null;
},
onSaved: (value)=> user_age = value,
decoration: InputDecoration(
hintText: 'Enter Age',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10)
),
),
),
);
final _male = Radio(
value: Gender.Male,
activeColor: Colors.black,
groupValue: _gender,
onChanged: (Gender value){
setState(() {
print(value);
_gender = value;
});
},
);
final _female = Radio(
activeColor: Colors.black,
value: Gender.Female,
groupValue: _gender,
onChanged: (Gender value){
setState(() {
print(value);
_gender = value;
});
},
);
final _others = Radio(
activeColor: Colors.black,
value: Gender.Others,
groupValue: _gender,
onChanged: (Gender value){
setState(() {
print(value);
_gender = value;
});
},
);
return Scaffold(
backgroundColor: Colors.yellow,
body: Container(
child: Form(
key: formkeyDetails,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text("Register",
style: TextStyle(fontSize: 64.0, fontWeight: FontWeight.bold),),
SizedBox(height: 50,),
_firstName,
SizedBox(height: 20,),
_lastName,
SizedBox(height: 20,),
_userAge,
SizedBox(height: 30,),
Row(
crossAxisAlignment: CrossAxisAlignment.center ,
children: <Widget>[
Text(" Gender: ", style: TextStyle(fontSize: 20.0),),
_male,
Text("Male"),
_female,
Text("Female"),
_others,
Text("Others"),
],
),
Row(
crossAxisAlignment: CrossAxisAlignment.center ,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
FloatingActionButton.extended(
heroTag: "prev_button",
backgroundColor: Colors.yellow,
foregroundColor: Colors.black,
onPressed: ()=> Navigator.push(context, MaterialPageRoute(builder: (context)=>UserLogin())),
label: Text("Prev", style: TextStyle(fontWeight: FontWeight.bold),)
),
FloatingActionButton.extended(
heroTag: "next_button",
backgroundColor: Colors.yellow,
foregroundColor: Colors.black,
onPressed: ()=> Navigator.push(context, MaterialPageRoute(builder: (context)=>UserReg())),
label: Text("Next", style: TextStyle(fontWeight: FontWeight.bold),)
),
],
),
],
),
),
),
);
}
}
Current page (which will print the contents of the previous page as well)
class UserReg extends StatefulWidget {
UserReg({this.auth});
final BaseAuth auth;
#override
State<StatefulWidget> createState() => _UserRegState();
}
class _UserRegState extends State<UserReg> {
final formkey = GlobalKey<FormState>();
static String emailValidator(String value) {
Pattern pattern =
r'^(([^<>()[\]\\.,;:\s#\"]+(\.[^<>()[\]\\.,;:\s#\"]+)*)|(\".+\"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$';
RegExp regex = new RegExp(pattern);
if (!regex.hasMatch(value)) {
return 'Email format is invalid';
} else {
return null;
}
}
static String pwdValidator(String value) {
if (value.length <= 6) {
return 'Password must be longer than 8 characters';
} else {
return null;
}
}
bool _validateAndSave()
{
final form2 = formkey.currentState;
final form1 = formkeyDetails.currentState;
if(form2.validate())
{
form.save();
return true;
}
return false;
}
void _validateAndSubmit() async
{
if(_validateAndSave()) {
try {
String userId = await Auth().signUp(rEmail, rPass);
await Auth().sendEmailVerification();
formkey.currentState.reset();
print('Registered! $userId, sent email verification');
}
catch (e) {
print('Error: $e');
}
}
}
final notValidIcon = Icon(
Icons.error,
color: Colors.pink,
);
static String rEmail;
static String rPass;
#override
Widget build(BuildContext context) {
//final userProvider = Provider.of<UserProvider>(context);
final _regEmail = Container(
padding: EdgeInsets.only(left: 10, right: 10),
child: TextFormField(
keyboardType: TextInputType.emailAddress,
autofocus: false,
validator: (value) {
if(value.isEmpty)
{
return 'Email cannot be empty';
}
else
emailValidator(value);
return null;
},
/*onChanged: (value){
userProvider.changeEmail(value);
},
*/
onSaved: (value)=> rEmail = value,
decoration: InputDecoration(
hintText: 'Enter Email Address',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10)
),
),
),
);
final _regpass = Container(
padding: EdgeInsets.only(left: 10, right: 10),
child: TextFormField(
obscureText: true,
autofocus: false,
validator: pwdValidator,
/*onChanged: (value){
userProvider.changePassword(value);
},
*/
onSaved: (value)=> rPass = value,
decoration: InputDecoration(
hintText: 'Enter password',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10)
),
),
),
);
final _confPass = Container(
padding: EdgeInsets.only(left: 10, right: 10),
child: TextFormField(
obscureText: true,
autofocus: false,
validator: (value){
if(value != rPass)
{
return("Password does not match");
}
return pwdValidator(value);
},
/*
onChanged: (value){
userProvider.changePassword(value);
},
*/
onSaved: (value)=> rPass = value,
decoration: InputDecoration(
hintText: 'Enter password',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10)
),
),
),
);
return new Scaffold(
resizeToAvoidBottomInset: true,
backgroundColor: Colors.yellow,
body: Container(
height: MediaQuery.of(context).size.height,
child: Form(
key: formkey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
SizedBox(height: MediaQuery.of(context).size.height *0.2,),
Text('Register',
style:TextStyle(
fontWeight: FontWeight.bold,
fontSize: 64,
),
),
SizedBox(height: 100,),
_regEmail,
SizedBox(height: 20,),
_regpass,
SizedBox(height:30),
//_confRegPass,
SizedBox(height: 30,),
FloatingActionButton.extended(
heroTag: "Register_Button",
backgroundColor: Colors.yellow,
foregroundColor: Colors.black,
onPressed: (){
_validateAndSubmit();
//userProvider.saveUser();
Navigator.pushReplacement(context, MaterialPageRoute(builder: (context)=>UserLogin()));
},
label: Text("Register", style: TextStyle(fontWeight: FontWeight.bold),)
),
SizedBox(height: 20,),
FlatButton(
child: Text('Already Registered? Sign in!'),
onPressed: ()=> Navigator.push(context, MaterialPageRoute(builder: (context)=>UserLogin())) ,
),
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
FloatingActionButton.extended(
heroTag: "prev_button1",
backgroundColor: Colors.yellow,
foregroundColor: Colors.black,
onPressed: ()=> Navigator.pop(context), //Navigator.push(context, MaterialPageRoute(builder: (context)=>UserDetails())),
label: Text("Prev", style: TextStyle(fontWeight: FontWeight.bold),)
),
],
),
],
),
),
),
);
}
}
Instead of directly going to the next page, you can validate the form in the current page itself using
onPressed: () {
// Validate returns true if the form is valid, otherwise false.
if (formKey.currentState.validate()) {
//Navigation Logic
}
}
And if you want the data from the previous page then you can refer to https://flutter.dev/docs/cookbook/navigation/passing-data