How to validate textfield when posting to firestore in flutter? [closed] - flutter

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 11 months ago.
Improve this question
I have added validator in TextField but validator is not working while submitting data. Save button saves the data with null value.
import 'package:cloud_firestore/cloud_firestore.dart';
import '../../screens/orders/order_success.dart';
import '../../services/global_methods.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
class PlaceOrder extends StatefulWidget {
static const routeName = '/place-order';
const PlaceOrder({Key? key}) : super(key: key);
#override
State<PlaceOrder> createState() => _PlaceOrderState();
}
class _PlaceOrderState extends State<PlaceOrder> {
final _formKey = GlobalKey<FormState>();
String? _name;
int? _phoneNumber;
String? _fullAddress;
String? _area;
String? _city;
String? _addressType;
final TextEditingController _addressController = TextEditingController();
String? _addressValue;
String? _deliverySlotValue;
final FirebaseAuth _auth = FirebaseAuth.instance;
late bool _isLoading = false;
final GlobalMethods _globalMethods = GlobalMethods();
final FocusNode _numberFocusNode = FocusNode();
#override
void initState() {
setState(() {
_isLoading = false;
});
super.initState();
}
#override
void dispose() {
_numberFocusNode.dispose();
super.dispose();
}
void _submitData() async {
final _isValid = _formKey.currentState!.validate();
FocusScope.of(context).unfocus();
if (_isValid) {
_formKey.currentState!.save();
}
try {
setState(() {
_isLoading = true;
});
final User? user = _auth.currentUser;
final _uid = user!.uid;
final orderId = ModalRoute.of(context)!.settings.arguments as String;
FirebaseFirestore.instance
.collection('orders')
.doc(orderId)
.set({
'userId': _uid,
'name': _name,
'phoneNumber': _phoneNumber,
'addressType': _addressType,
'address': _fullAddress,
'area': _area,
'city': _city,
'deliverySlot': _deliverySlotValue,
}, SetOptions(merge: true));
} catch (error) {
_globalMethods.authDialog(context, error.toString());
} finally {
setState(() {
_isLoading = false;
});
Navigator.of(context).pushReplacementNamed(OrderSuccess.routeName);
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Add new address'),
),
body: Form(
key: _formKey,
child: Padding(
padding: const EdgeInsets.all(16.0),
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Row(
children: [
DropdownButton<String>(
items: const [
DropdownMenuItem<String>(
child: Text('Home'),
value: 'Home',
),
DropdownMenuItem<String>(
child: Text('Office'),
value: 'Office',
),
DropdownMenuItem<String>(
child: Text('Other'),
value: 'Other',
),
],
onChanged: (value) {
setState(() {
_addressValue = value.toString();
_addressController.text = value.toString();
print(_addressType);
});
},
hint: const Text('Select address type'),
value: _addressValue,
),
const SizedBox(
width: 10,
),
Expanded(
child: TextFormField(
key: const ValueKey('addressType'),
controller: _addressController,
validator: (val) {
if (val!.isEmpty) {
return 'Please select address type';
}
return null;
},
decoration: const InputDecoration(
labelText: 'Select your address type',
),
onSaved: (val) {
_addressType = val.toString();
},
),
),
],
),
TextFormField(
onSaved: (value) {
_name = value!;
},
textInputAction: TextInputAction.next,
key: const ValueKey('name'),
validator: (value) {
if (value!.isEmpty) {
return 'Please enter your name';
}
return null;
},
decoration: InputDecoration(
labelText: 'Name',
filled: true,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
),
prefixIcon: const Icon(Icons.location_city),
),
),
const SizedBox(height: 8),
TextFormField(
onSaved: (value) {
_fullAddress = value!;
},
textInputAction: TextInputAction.next,
key: const ValueKey('streetAddress'),
validator: (value) {
if (value!.isEmpty) {
return 'Please enter your address';
}
return null;
},
decoration: InputDecoration(
labelText: 'Address',
filled: true,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
),
prefixIcon: const Icon(Icons.location_city),
),
),
const SizedBox(height: 8),
TextFormField(
onSaved: (value) {
_area = value!;
},
textInputAction: TextInputAction.next,
key: const ValueKey('area'),
validator: (value) {
if (value!.isEmpty) {
return 'Please enter your area';
}
return null;
},
decoration: InputDecoration(
labelText: 'Area',
filled: true,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
),
prefixIcon: const Icon(Icons.location_city),
),
),
const SizedBox(height: 8),
TextFormField(
onSaved: (value) {
_city = value!;
},
textInputAction: TextInputAction.next,
key: const ValueKey('city'),
validator: (value) {
if (value!.isEmpty) {
return 'Please enter your city';
}
return null;
},
decoration: InputDecoration(
labelText: 'City',
filled: true,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
),
prefixIcon: const Icon(Icons.location_city),
),
),
const SizedBox(height: 8),
TextFormField(
onSaved: (value) {
_phoneNumber = int.parse(value!);
},
textInputAction: TextInputAction.next,
// keyboardType: TextInputType.emailAddress,
onEditingComplete: () =>
FocusScope.of(context).requestFocus(_numberFocusNode),
key: const ValueKey('number'),
validator: (value) {
if (value!.length < 10) {
return 'Phone number must be 10 units';
}
return null;
},
decoration: InputDecoration(
labelText: 'Phone Number',
filled: true,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
),
prefixIcon: const Icon(Icons.phone),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
DropdownButton<String>(
items: const [
DropdownMenuItem<String>(
child: Text('11:00am to 1:00pm'),
value: '11:00am to 1:00pm',
),
DropdownMenuItem<String>(
child: Text('1:00pm to 3:00pm'),
value: '1:00pm to 3:00pm',
),
DropdownMenuItem<String>(
child: Text('3:00pm to 5:00pm'),
value: '3:00pm to 5:pm',
),
DropdownMenuItem<String>(
child: Text('5:00pm to 7:00pm'),
value: '5:00pm to 7:00pm',
),
DropdownMenuItem<String>(
child: Text('7:00pm to 9:pm'),
value: '7:00pm to 9:pm',
),
],
onChanged: (value) {
setState(() {
_deliverySlotValue = value.toString();
});
},
hint: const Text('Select Delivery Slot'),
value: _deliverySlotValue,
),
],
),
Padding(
padding: const EdgeInsets.all(48.0),
child: SizedBox(
child: ElevatedButton(
onPressed: _submitData,
child: _isLoading
? const CircularProgressIndicator()
: const Text(
'S U B M I T',
style: TextStyle(color: Colors.white),
),
),
),
),
],
),
),
),
),
);
}
}

It appears that the problem is a simple mistake with your control flow in the following code (see // comment):
void _submitData() async {
final _isValid = _formKey.currentState!.validate();
FocusScope.of(context).unfocus();
if (_isValid) {
_formKey.currentState!.save();
} // <----- this should not be here!
try {
setState(() {
_isLoading = true;
});
final User? user = _auth.currentUser;
final _uid = user!.uid;
final orderId = ModalRoute.of(context)!.settings.arguments as String;
FirebaseFirestore.instance
.collection('orders')
.doc(orderId)
.set({
'userId': _uid,
'name': _name,
'phoneNumber': _phoneNumber,
'addressType': _addressType,
'address': _fullAddress,
'area': _area,
'city': _city,
'deliverySlot': _deliverySlotValue,
}, SetOptions(merge: true));
} catch (error) {
_globalMethods.authDialog(context, error.toString());
} finally {
setState(() {
_isLoading = false;
});
Navigator.of(context).pushReplacementNamed(OrderSuccess.routeName);
}
}
As you can see, even if the user input is not valid, you still continue to upload the results to Firebase anyway.
Try correcting like this:
void _submitData() async {
final _isValid = _formKey.currentState!.validate();
FocusScope.of(context).unfocus();
if (_isValid) {
_formKey.currentState!.save();
try {
setState(() {
_isLoading = true;
});
final User? user = _auth.currentUser;
final _uid = user!.uid;
final orderId = ModalRoute.of(context)!.settings.arguments as String;
FirebaseFirestore.instance.collection('orders').doc(orderId).set({
'userId': _uid,
'name': _name,
'phoneNumber': _phoneNumber,
'addressType': _addressType,
'address': _fullAddress,
'area': _area,
'city': _city,
'deliverySlot': _deliverySlotValue,
}, SetOptions(merge: true));
} catch (error) {
_globalMethods.authDialog(context, error.toString());
} finally {
setState(() {
_isLoading = false;
});
Navigator.of(context).pushReplacementNamed(OrderSuccess.routeName);
}
} else {
// do nothing
}
}

The only possible reason is because of _addressType it's initial value is null
since it's a String? variable so if the user didn't select a "Delivery Slot"
the result of it after saving would be null,
what you need to do, it to check the value of _addressType if it's null or not then proceed to saving the form because your form doesn't check it if it's null or not.

You can add the form validator to the submit button itself. The below code works when you click on the submit button.
Padding(
padding: const EdgeInsets.all(48.0),
child: SizedBox(
child: ElevatedButton(
onPressed: (){
if (_formKey.currentState!.validate()){
_submitData;
}
},
child: _isLoading
? const CircularProgressIndicator()
: const Text(
'S U B M I T',
style: TextStyle(color: Colors.white),
),
),
),
),

Related

Image uploads in Firebase but not the data fetched from TextFormFields and dropdownbutton

Flutter beginner here. Working on a flutter project where I can submit a form where I can upload it's content in firebase. I took the data from TextFormField and DropDownButton and the images from ImagePicker. I can upload the image file perfectly to the firebase but the data are not uploading. Here is the code:
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_storage/firebase_storage.dart';
import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:image_picker/image_picker.dart';
import 'package:path/path.dart' as path;
class AddDoctor extends StatefulWidget {
#override
State<AddDoctor> createState() => AddDoctorState();
}
class AddDoctorState extends State<AddDoctor> {
late String name;
late int age;
late String description;
String specialistValue = 'Select Specialist';
String hospitalValue = 'Select Hospital';
List<String> imageUrlList = [];
final controllerName = TextEditingController();
final controllerAge = TextEditingController();
final controllerDesciption = TextEditingController();
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
final FirebaseStorage _firebaseStorage = FirebaseStorage.instance;
final FirebaseFirestore _firestore = FirebaseFirestore.instance;
final ImagePicker _picker = ImagePicker();
XFile? image;
void pickDoctorImage() async {
try {
final pickedImage = await _picker.pickImage(source: ImageSource.gallery);
setState(() {
image = pickedImage!;
});
} catch (e) {}
}
Widget displayImage() {
return Image.file(File(image!.path));
}
Future<void> uploadImage() async {
Reference ref =
_firebaseStorage.ref('products/${path.basename(image!.path)}');
await ref.putFile(File(image!.path)).whenComplete(() async {
await ref.getDownloadURL().then((value) {
imageUrlList.add(value);
});
});
}
void uploadInfo() async {
CollectionReference infoRef = _firestore.collection('DoctorList');
await infoRef.doc().set({
'name': name,
'age': age,
'description': description,
'specialist': specialistValue,
'hospital': hospitalValue,
'doctorImage': imageUrlList,
}).whenComplete(() {
Navigator.pop(context);
});
}
void uploadDoctorInfo() async {
await uploadImage().whenComplete(() => uploadInfo);
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color(0xFFD9E4EE),
appBar: AppBar(
title: const Text('Add Doctor'),
actions: [
IconButton(
icon: const Icon(Icons.menu),
onPressed: () {},
),
],
),
body: Form(
key: _formKey,
child: ListView(
padding: const EdgeInsets.all(16),
children: <Widget>[
TextFormField(
keyboardType: TextInputType.name,
validator: (value) {
if (value!.isEmpty) {
return 'Please Name must not be empty';
} else {
return null;
}
},
controller: controllerName,
decoration: const InputDecoration(
label: Text('Name'),
),
onSaved: (value) {
name = value!;
},
),
const SizedBox(height: 10),
TextFormField(
keyboardType: TextInputType.number,
validator: (value) {
if (value!.isEmpty) {
return 'Please Age must not be empty';
} else {
return null;
}
},
controller: controllerAge,
decoration: const InputDecoration(
label: Text('Age'),
),
onSaved: (value) {
age = int.parse(value!);
},
),
const SizedBox(height: 10),
DropdownButton(
borderRadius: BorderRadius.circular(30),
value: specialistValue,
items: specialistList.map<DropdownMenuItem<String>>((e) {
return DropdownMenuItem(
value: e,
child: Text(e),
);
}).toList(),
onChanged: (String? value) {
setState(() {
specialistValue = value!;
});
},
),
DropdownButton(
borderRadius: BorderRadius.circular(30),
value: hospitalValue,
items: hospitalList.map<DropdownMenuItem<String>>((e) {
return DropdownMenuItem(
value: e,
child: Text(e),
);
}).toList(),
onChanged: (String? value) {
setState(() {
hospitalValue = value!;
});
},
),
const SizedBox(height: 10),
TextFormField(
keyboardType: TextInputType.number,
validator: (value) {
if (value!.isEmpty) {
return 'Please Description must not be empty';
} else {
return null;
}
},
maxLength: 100,
maxLines: 3,
controller: controllerDesciption,
decoration: const InputDecoration(
label: Text('Description'),
),
onChanged: (value) {
description = value;
},
),
const SizedBox(height: 10),
// CircleAvatar(
// radius: 50,
// backgroundImage: image != null ? FileImage(image) : null,
// ),
InkWell(
onTap: () {
setState(() {
image = null;
});
},
child: Container(
padding: const EdgeInsetsDirectional.only(top: 60),
height: 150,
width: 150,
decoration: const BoxDecoration(
color: Colors.blue,
shape: BoxShape.circle,
),
child: Center(
child: image != null
? displayImage()
: const Text(
'You have not pick any image',
style: TextStyle(fontSize: 11),
textAlign: TextAlign.center,
),
)),
),
const SizedBox(height: 10),
ElevatedButton(
onPressed: () {
pickDoctorImage();
},
child: const Text('Upload Image'),
),
const SizedBox(height: 10),
ElevatedButton(
child: const Text('Submit'),
onPressed: () {
uploadDoctorInfo();
},
),
],
),
),
);
}
}
There aren't any error in the file either. I can't figure out where the source of the problem is.
Fixed it. The problem was in
void uploadDoctorInfo() async {
await uploadImage().whenComplete(() => uploadInfo);
}
I changed it to
void uploadDoctorInfo() async {
await uploadImage().whenComplete(uploadInfo);
}
And now it's working fine
You should add for the new entry instead set data in collection. Try using the following code
void uploadInfo() async {
CollectionReference infoRef = _firestore.collection('DoctorList');
await infoRef.add({
'name': name,
'age': age,
'description': description,
'specialist': specialistValue,
'hospital': hospitalValue,
'doctorImage': imageUrlList,
}).whenComplete(() {
Navigator.pop(context);
});
}
Edited
Your are referencing uploadInfo function instead of call that. updateInfo should be called by adding (), so uploadDoctorInfo will be look like.
void uploadDoctorInfo() async {
await uploadImage().whenComplete(() => uploadInfo());
}
or
void uploadDoctorInfo() async {
await uploadImage().whenComplete(uploadInfo);
}

how to hide email field when a user logged with phone authentication in flutter firebase?

i have an buying and selling app in which a user can sign up with different methods like google, phone authentication and email so my question is when a user log in with phone authentication how to hide the email field from user profile.
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:mobihub_2/Screens/email_verifcation_screen.dart';
import 'package:mobihub_2/Screens/search_screens/search_filter.dart';
import '../../Models/user_model.dart';
import '../home_page.dart';
class ProfileDetailScreen extends StatefulWidget {
final String? name;
final String? email;
final String? location;
final String? gender;
final bool number;
const ProfileDetailScreen(
{Key? key, required this.name, this.email, this.location, required this.gender,required this.number})
: super(key: key);
#override
State<ProfileDetailScreen> createState() => _ProfileDetailScreenState();
}
class _ProfileDetailScreenState extends State<ProfileDetailScreen> {
final _auth=FirebaseAuth.instance;
var collectionRef = FirebaseFirestore.instance.collection('UsersDetails');
var dropDownValue;
bool loading = false;
var name = TextEditingController();
var emailC = TextEditingController();
var passwordC =TextEditingController();
var city = TextEditingController();
#override
void initState() {
if (widget.location != null && widget.location!.isNotEmpty) {
setState(() {
city = TextEditingController(text: widget.location);
});
}
if (widget.name != null && widget.name!.isNotEmpty) {
setState(() {
name = TextEditingController(text: widget.name);
});
}
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.amberAccent,
foregroundColor: Colors.blueGrey,
title: Text('Profile'),
elevation: 0,
),
body: SafeArea(
child: Padding(
padding: EdgeInsets.all(20),
child: Column(
children: [
TextFormField(
onChanged: (value) {
setState(() {
name = TextEditingController(text: (value));
});
},
initialValue: name.text,
decoration: InputDecoration(
hintText: 'Name',
prefixIcon: Icon(Icons.person_outline_outlined),
suffixIcon: Icon(Icons.edit_outlined),
),
),
SizedBox(
height: 20,
),
TextFormField(
onTap: (){
showDialog(context: context, builder: (context) {
return AlertDialog(
content: Text('Want to change your email?'),
actions: [
Padding(padding:EdgeInsets.all(10),
child: Column(
children: [
TextFormField(
controller:emailC,
decoration: InputDecoration(
hintText: 'new email',
prefixIcon: Icon(Icons.email_outlined),
),
),
SizedBox(height: 10,),
TextFormField(
controller: passwordC,
decoration: InputDecoration(
hintText: 'old Password',
prefixIcon: Icon(Icons.lock_open_outlined),
),
),
SizedBox(height: 5,),
ElevatedButton(onPressed: ()async{
loading=true;
await changeEmail(
email: emailC.text,password: passwordC.text
);
loading=false;
}, child:loading?Center(child: CircularProgressIndicator(color:Colors.black,),): Text('Submit'))
],
),
)
],
);
}
);
},
readOnly: true,
initialValue: widget.email,
// onChanged: (value) {
// setState(() {
// email = value;
// });
// },
decoration: InputDecoration(
hintText: 'Email',
prefixIcon: Icon(Icons.email_outlined),
suffixIcon: IconButton(onPressed: () {
}, icon: Icon(Icons.edit_outlined),),
),
),
SizedBox(
height: 20,
),
TextFormField(
readOnly: true,
initialValue: widget.number.toString(),
decoration: InputDecoration(
hintText: 'Phone number',
prefixIcon: Icon(Icons.email_outlined),
suffixIcon: IconButton(onPressed: () {
}, icon: Icon(Icons.edit_outlined),),
),
),
SizedBox(
height: 20,
),
TextFormField(
onTap: (){
setState(() async {
city.text = await Navigator.push(context,
MaterialPageRoute(builder: (_) => SearchScreen()));
});
},
readOnly: true,
controller: city,
decoration: InputDecoration(
hintText: 'Address',
prefixIcon: Icon(Icons.location_city_outlined),
suffixIcon: IconButton(onPressed: () {
}, icon: Icon(Icons.arrow_drop_down_circle_outlined)),
),
),
SizedBox(
height: 20,
),
DropdownButtonFormField(
decoration: InputDecoration(
prefixIcon: Icon(Icons.person,),
),
hint: Text(widget.gender!.isNotEmpty
? widget.gender!
: 'Select Gender'),
items: ['Male', 'Female'].map(
(val) {
return DropdownMenuItem<String>(
value: val,
child: Text(val),
);
},
).toList(), onChanged: (String? val) {
setState(
() {
dropDownValue = val;
},
);
},),
SizedBox(
height: 20,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
OutlinedButton(onPressed: () {}, child: Text('Cancel')),
OutlinedButton(
style: OutlinedButton.styleFrom(
backgroundColor: Colors.amberAccent),
onPressed: () async {
setState(() {
loading = true;
});
await postDetailsToFirestore();
setState(() {
loading = false;
});
},
child: loading
? Center(
child: CircularProgressIndicator(color: Colors.blue,))
: Text('Save')),
],
),
],
),
),
),
);
}
Future<void> changeEmail(
{required String email, required String password}) async {
//showLoadingDialog(message: AppTexts.updating);
try {
User user = _auth.currentUser!;
DocumentReference ref=collectionRef.doc(user.uid);
final cred =
EmailAuthProvider.credential(email: user.email!, password: passwordC.text);
user.reauthenticateWithCredential(cred).then((value) {
user.updateEmail(email).then((_) async {
await ref.update({'email': email}).then((value) async {
// go to root page
await _auth.currentUser!.sendEmailVerification();
Fluttertoast.showToast(msg: 'Verification Email has been sent to you');
await _auth.signOut();
});
setState(() {
Navigator.pushAndRemoveUntil(context, MaterialPageRoute(builder: (_)=>VerificationScreen()), (route) => false);
});
}).catchError((error) {
Fluttertoast.showToast(msg: error.toString());
});
}).catchError((err) {
Fluttertoast.showToast(msg: err.toString());
});
} on Exception catch (err) {
Fluttertoast.showToast(msg: err.toString());
// showErrorDialog(err.toString());
}
}
postDetailsToFirestore() async {
var auth = FirebaseAuth.instance;
FirebaseFirestore firebaseFirestore = FirebaseFirestore.instance;
User? user = auth.currentUser;
UserModel userModel = UserModel();
// writing all the values
userModel.email = user!.email;
userModel.uid = user.uid;
userModel.fullName = name.text;
userModel.phone = user.phoneNumber;
userModel.location = city.text;
userModel.joindate = '';
userModel.gender = dropDownValue;
await firebaseFirestore
.collection("UsersDetails")
.doc(user.uid)
.update(userModel.toMap());
Fluttertoast.showToast(msg: "Account Updated successfully :) ");
Navigator.pushAndRemoveUntil(
(context),
MaterialPageRoute(builder: (context) => const Home()),
(route) => false);
}
}
when a user login with email the phone field will hide and when user login with phone the email field will hide. If anybody can help me it would be very appreciable.Thank you

I'm making a authentication login form then I face this error

I'm making authentication login form and want to connect submitAuthForm Function to the AuthForm. That's why I pass reference in the AuthForm. I am beginner. Please help me to solve this problem (The argument type void Function(String, String, String, bool) can't be assigned to the parameter type void Function(String, String, String, bool)
Thanks.
class AuthScreen extends StatefulWidget {
#override
_AuthScreenState createState() => _AuthScreenState();
}
class _AuthScreenState extends State<AuthScreen> {
void _submitAuthForm(
String email,
String password,
String username,
bool isLogin) {
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Theme.of(context).primaryColor,
body: Authform(_submitAuthForm,)/*( The argument type 'void Function(String, String, String, bool)' can't be assigned to the parameter type 'Void Function(String, String, String, bool)'.*/)
);
}
}
class Authform extends StatefulWidget {
Authform(this.submitFN);
final Void Function(
String email, String password, String username, bool isLogin) submitFN;
#override
_AuthformState createState() => _AuthformState();
}
class _AuthformState extends State<Authform> {
final _formKey = GlobalKey<FormState>();
var _isLogin = true;
var _userEmail;
var _userName;
var _userPassword;
void _trySubmit() {
final isValid = _formKey.currentState!.validate();
FocusScope.of(context).unfocus();
if (isValid) {
_formKey.currentState!.save();
widget.submitFN(_userEmail,_userPassword,_userName,_isLogin);
}
}
#override
Widget build(BuildContext context) {
return Center(
child: Card(
margin: EdgeInsets.all(20),
child: SingleChildScrollView(
child: Padding(
padding: EdgeInsets.all(16),
child: Form(
key: _formKey,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
TextFormField(
key: ValueKey('email'),
validator: (value) {
if (value!.isEmpty || !value.contains('#')) {
return 'please enter valid email address';
}
return null;
},
keyboardType: TextInputType.emailAddress,
decoration: InputDecoration(
icon: Icon(
Icons.mail,
color: Colors.orange,
),
labelText: 'Email Addess'),
onSaved: (value) {
_userEmail = value;
},
),
if (!_isLogin)
TextFormField(
key: ValueKey('username'),
validator: (value) {
if (value!.isEmpty || value.length < 4) {
return 'Username is short enter atleast 4 characters ';
}
},
decoration: InputDecoration(
icon: Icon(
Icons.person,
color: Colors.orange,
),
labelText: 'Username'),
onSaved: (value) {
_userName = value;
},
),
TextFormField(
key: ValueKey('password'),
validator: (value) {
if (value!.isEmpty || value.length < 7) {
return 'Password must be atleast 7 characters long';
}
return null;
},
decoration: InputDecoration(
icon: Icon(
Icons.lock,
color: Colors.orange,
),
labelText: 'password',
),
obscureText: true,
onSaved: (value) {
_userPassword = value;
},
),
SizedBox(
height: 12,
),
ElevatedButton(
onPressed: _trySubmit,
child: Text(_isLogin ? 'Login' : 'Signup'),
style: ElevatedButton.styleFrom(onPrimary: Colors.white),
),
TextButton(
onPressed: () {
setState(() {
_isLogin = !_isLogin;
});
},
child: Text(_isLogin
? 'Create new account'
: 'I already have a acoount'))
],
)),
)),
),
);
}
}
When declaring a function or variable you have follow proper declaring method to avoid unusual issues. You have declare your function using Void the V is in capital case there but it must be in small case like void. Juts change this like :
final Void Function(
to
final void Function(
import 'package:flutter/material.dart';
void main(List<String> args) {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(),
home: AuthScreen(),
);
}
}
class AuthScreen extends StatefulWidget {
#override
_AuthScreenState createState() => _AuthScreenState();
}
class _AuthScreenState extends State<AuthScreen> {
void _submitAuthForm(
String email, String password, String username, bool isLogin) {}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Theme.of(context).primaryColor,
body: Authform(
_submitAuthForm,
));
}
}
class Authform extends StatefulWidget {
Authform(this.submitFN);
final void Function(
String email, String password, String username, bool isLogin) submitFN;
#override
_AuthformState createState() => _AuthformState();
}
class _AuthformState extends State<Authform> {
final _formKey = GlobalKey<FormState>();
var _isLogin = true;
var _userEmail;
var _userName;
var _userPassword;
void _trySubmit() {
final isValid = _formKey.currentState!.validate();
FocusScope.of(context).unfocus();
if (isValid) {
_formKey.currentState!.save();
widget.submitFN(_userEmail, _userPassword, _userName, _isLogin);
}
}
#override
Widget build(BuildContext context) {
return Center(
child: Card(
margin: EdgeInsets.all(20),
child: SingleChildScrollView(
child: Padding(
padding: EdgeInsets.all(16),
child: Form(
key: _formKey,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
TextFormField(
key: ValueKey('email'),
validator: (value) {
if (value!.isEmpty || !value.contains('#')) {
return 'please enter valid email address';
}
return null;
},
keyboardType: TextInputType.emailAddress,
decoration: InputDecoration(
icon: Icon(
Icons.mail,
color: Colors.orange,
),
labelText: 'Email Addess'),
onSaved: (value) {
_userEmail = value;
},
),
if (!_isLogin)
TextFormField(
key: ValueKey('username'),
validator: (value) {
if (value!.isEmpty || value.length < 4) {
return 'Username is short enter atleast 4 characters ';
}
},
decoration: InputDecoration(
icon: Icon(
Icons.person,
color: Colors.orange,
),
labelText: 'Username'),
onSaved: (value) {
_userName `enter code here`= value;
},
),
TextFormField(
key: ValueKey('password'),
validator: (value) {
if (value!.isEmpty || value.length < 7) {
return 'Password must be atleast 7 characters long';
}
return null;
},
decoration: InputDecoration(
icon: Icon(
Icons.lock,
color: Colors.orange,
),
labelText: 'password',
),
obscureText: true,
onSaved: (value) {
_userPassword = value;
},
),
SizedBox(
height: 12,
),
ElevatedButton(
onPressed: _trySubmit,
child: Text(_isLogin ? 'Login' : 'Signup'),
style: ElevatedButton.styleFrom(onPrimary: Colors.white),
),
TextButton(
onPressed: () {
setState(() {
_isLogin = !_isLogin;
});
},
child: Text(_isLogin
? 'Create new account'
: 'I already have a acoount'))
],
)),
)),
),
);
}
}
account_screen.dart
child: AuthForm(
submitFn: _submitAuthForm,
),

type 'Null' is not a subtype of type 'File' of 'image' flutter problem

I uploaded my image to FireStore. When I am creating an image it's perfectly ok everything uploading perfectly. After SignUp I can easily go to the user profile and can see the user name and email. But when I log out from the user profile and from my LOGIN from when providing existing email and password which I have created already then the Exception is thrown. I am not getting the issue. Exception has occurred.
_TypeError (type 'Null' is not a subtype of type 'File' of 'image')
import 'dart:io';
import '../picker/user_image_picker.dart';
import 'package:flutter/material.dart';
class AuthForm extends StatefulWidget {
AuthForm(this.submitFn, this.isLoading);
final bool isLoading;
var submitFn;
void function(
String email,
String password,
String userName,
File image,
bool isLogin,
BuildContext ctx,
);
#override
_AuthFormState createState() => _AuthFormState();
#override
noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}
class _AuthFormState extends State<AuthForm> {
final _formKey = GlobalKey<FormState>();
var _isLogin = true;
var _userEmail = '';
var _userName = '';
var _userPasssword = '';
File? userImageFile;
void pickedImage(File image) {
userImageFile = image;
}
void _trySubmit() {
final isValid = _formKey.currentState!.validate();
FocusScope.of(context).unfocus();
if (userImageFile == null && !_isLogin) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Please Pick an Image.'),
backgroundColor: Theme.of(context).errorColor,
),
);
return;
}
if (isValid) {
_formKey.currentState?.save();
print(_userEmail);
print(_userName);
print(_userPasssword);
print(' Good to go ');
widget.submitFn(
_userEmail.trim(),
_userPasssword.trim(),
_userName.trim(),
userImageFile,
_isLogin,
context,
);
} else {
print('Form is not valid');
}
}
#override
Widget build(BuildContext context) {
return Card(
margin: EdgeInsets.all(20),
child: SingleChildScrollView(
child: Padding(
padding: EdgeInsets.all(16),
child: Form(
key: _formKey,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
if (!_isLogin) UserImagePicker(pickedImage),//this is my image file
TextFormField(
key: ValueKey('email'),
onSaved: (value) {
_userEmail = value!;
},
validator: (value) {
if (value!.isEmpty ||
!value.contains(RegExp(
'^[a-zA-Z0-9+_.-]+#[a-zA-Z0-9.-]+.[a-z]+.[com]'))) {
return 'enter valid Email';
//print('Email validation is not ok');
} else {
return null;
}
},
keyboardType: TextInputType.emailAddress,
decoration: InputDecoration(
labelText: 'Email Address', icon: Icon(Icons.email)),
),
if (!_isLogin)
TextFormField(
key: ValueKey('userName'),
onSaved: (value) {
_userName = value!;
},
validator: (value) {
if (value == null || value.length < 4) {
return 'Enter At least 4 charaters ';
}
return null;
},
decoration: InputDecoration(
labelText: 'User Name', icon: Icon(Icons.person)),
),
TextFormField(
key: ValueKey('password'),
onSaved: (value) {
_userPasssword = value!;
},
obscureText: true,
validator: (value) {
if (value == null || value.isEmpty || value.length < 7) {
return 'Enter at least 7 Digits';
}
return null;
},
decoration: InputDecoration(
labelText: 'Password',
icon: Icon(
Icons.security,
),
),
),
SizedBox(
height: 20,
),
if (widget.isLoading) CircularProgressIndicator(),
if (!widget.isLoading)
ElevatedButton(
child: Text(_isLogin ? 'Login' : 'Signup'),
onPressed: _trySubmit,
),
if (widget.isLoading) CircularProgressIndicator(),
if (!widget.isLoading)
TextButton(
style: TextButton.styleFrom(
primary: Theme.of(context).primaryColor,
),
child: Text(_isLogin
? 'Create New Account'
: 'I already have an account'),
onPressed: () {
setState(
() {
_isLogin = !_isLogin;
},
);
},
)
],
),
),
),
),
);
}
}
Looks like userImageFile is null. This happen because this variable is nullable, and when it gets passed to submitFn (which weirdly is a dynamic variable...?) it throws, because it expects a non-nullable image parameter.

How to pass the data from the form to the next screen in flutter?

I'm building an application that has a pretty long form with a lot of text fields, so I divided the text fields into multiple screens. It got three screens, the first screen has some common text fields such as phone, website, email, etc. The second screen has some more text fields and the same with the third screen. I'm trying to display all the details from the three forms at the end on a different screen.
I want to display all the details in the end when I hit the 'Done' button on a different page.
Here's the code for the first screen which has the first form:-
import 'package:flutter/material.dart';
import 'package:instaskool/model.dart';
import 'package:validators/validators.dart' as validator;
import 'package:instaskool/home_screens/homescreen_student.dart';
import 'package:instaskool/home_screens/homescreen_school.dart';
import 'package:instaskool/screens/school_signup_two.dart';
class SchoolReg extends StatefulWidget {
#override
_SchoolRegState createState() => _SchoolRegState();
}
class _SchoolRegState extends State<SchoolReg> {
final _formKey = GlobalKey<FormState>();
School school = School();
#override
Widget build(BuildContext context) {
return Scaffold(
body: SingleChildScrollView(
child: new Form(
key: _formKey,
child: Column(
children: <Widget>[
Container(
margin: EdgeInsets.only(top: 130),
alignment: Alignment.topCenter,
child: MyTextFormField(
hintText: 'School name',
validator: (String value) {
if (value.isEmpty) {
return 'Enter your school name';
}
return null;
},
onSaved: (String value) {
school.schoolName = value;
},
),
),
MyTextFormField(
hintText: 'Phone',
validator: (String value) {
if (value.isEmpty) {
return 'Enter the phone number';
}
return null;
},
onSaved: (String value) {
school.schoolPhone = value;
},
),
MyTextFormField(
hintText: 'Email',
validator: (String value) {
if (value.isEmpty) {
return 'Enter the email address';
}
return null;
},
onSaved: (String value) {
school.schoolEmail = value;
},
),
MyTextFormField(
hintText: 'School Website',
isEmail: true,
validator: (String value) {
if (value.isEmpty) {
return "Enter the school's website";
}
return null;
},
onSaved: (String value) {
school.schoolWebsite = value;
},
),
RaisedButton(
color: Colors.blueAccent,
onPressed: () {
if (_formKey.currentState.validate()) {
_formKey.currentState.save();
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SchoolRegTwo()));
}
},
child: Text(
'Next',
style: TextStyle(
color: Colors.white,
),
),
)
],
),
),
),
);
}
}
class MyTextFormField extends StatelessWidget {
final String hintText;
final Function validator;
final Function onSaved;
final bool isPassword;
final bool isEmail;
MyTextFormField({
this.hintText,
this.validator,
this.onSaved,
this.isPassword = false,
this.isEmail = false,
});
#override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.all(8.0),
child: TextFormField(
decoration: InputDecoration(
hintText: hintText,
contentPadding: EdgeInsets.all(15.0),
border: InputBorder.none,
filled: true,
fillColor: Colors.grey[200],
),
obscureText: isPassword ? true : false,
validator: validator,
onSaved: onSaved,
keyboardType: isEmail ? TextInputType.emailAddress : TextInputType.text,
),
);
}
}
Here's the code for the second form:-
import 'package:flutter/material.dart';
import 'package:instaskool/model.dart';
import 'package:validators/validators.dart' as validator;
import 'package:instaskool/home_screens/homescreen_student.dart';
import 'package:instaskool/home_screens/homescreen_school.dart';
import 'package:instaskool/screens/school_signup_three.dart';
class SchoolRegTwo extends StatefulWidget {
#override
_SchoolRegTwoState createState() => _SchoolRegTwoState();
}
class _SchoolRegTwoState extends State<SchoolRegTwo> {
final _formKey = GlobalKey<FormState>();
SchoolDet schooldet = SchoolDet();
#override
Widget build(BuildContext context) {
return Scaffold(
body: SingleChildScrollView(
child: new Form(
key: _formKey,
child: Column(
children: <Widget>[
Container(
margin: EdgeInsets.only(top: 130),
alignment: Alignment.topCenter,
child: MyTextFormField(
hintText: 'School address 1',
validator: (String value) {
if (value.isEmpty) {
return "Enter your school's address";
}
return null;
},
onSaved: (String value) {
schooldet.addressOne = value;
},
),
),
MyTextFormField(
hintText: 'School address 2',
validator: (String value) {
if (value.isEmpty) {
return "Enter the school's address";
}
return null;
},
onSaved: (String value) {
schooldet.addressTwo = value;
},
),
MyTextFormField(
hintText: 'City',
validator: (String value) {
if (value.isEmpty) {
return 'Enter the city';
}
return null;
},
onSaved: (String value) {
schooldet.city = value;
},
),
MyTextFormField(
hintText: 'Pincode',
isEmail: true,
validator: (String value) {
if (value.isEmpty) {
return "Enter the pincode";
}
return null;
},
onSaved: (String value) {
schooldet.pincode = value;
},
),
MyTextFormField(
hintText: 'State',
isEmail: true,
validator: (String value) {
if (value.isEmpty) {
return "Enter the state";
}
return null;
},
onSaved: (String value) {
schooldet.state = value;
},
),
RaisedButton(
color: Colors.blueAccent,
onPressed: () {
if (_formKey.currentState.validate()) {
_formKey.currentState.save();
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SchoolRegThree(schooldet: this.schooldet)));
}
},
child: Text(
'Next',
style: TextStyle(
color: Colors.white,
),
),
)
],
),
),
),
);
}
}
class MyTextFormField extends StatelessWidget {
final String hintText;
final Function validator;
final Function onSaved;
final bool isPassword;
final bool isEmail;
MyTextFormField({
this.hintText,
this.validator,
this.onSaved,
this.isPassword = false,
this.isEmail = false,
});
#override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.all(8.0),
child: TextFormField(
decoration: InputDecoration(
hintText: hintText,
contentPadding: EdgeInsets.all(15.0),
border: InputBorder.none,
filled: true,
fillColor: Colors.grey[200],
),
obscureText: isPassword ? true : false,
validator: validator,
onSaved: onSaved,
keyboardType: isEmail ? TextInputType.emailAddress : TextInputType.text,
),
);
}
}
Here's the code for the third form:-
import 'package:flutter/material.dart';
import 'package:instaskool/model.dart';
import 'package:validators/validators.dart' as validator;
import 'package:instaskool/home_screens/homescreen_student.dart';
import 'package:instaskool/home_screens/homescreen_school.dart';
import 'package:instaskool/screens/school_signup_three.dart';
import 'package:instaskool/screens/school_code.dart';
class SchoolRegThree extends StatefulWidget {
School school;
SchoolRegThree({this.school, SchoolDet schooldet});
#override
_SchoolRegThreeState createState() => _SchoolRegThreeState();
}
class _SchoolRegThreeState extends State<SchoolRegThree> {
final _formKey = GlobalKey<FormState>();
SchoolUser schooluser = SchoolUser();
#override
Widget build(BuildContext context) {
return Scaffold(
body: SingleChildScrollView(
child: new Form(
key: _formKey,
child: Column(
children: <Widget>[
Container(
margin: EdgeInsets.only(top: 100),
child: MyTextFormField(
hintText: 'Username',
isPassword: true,
validator: (String value) {
if (value.length < 5) {
return 'Username should be at least 5 characters long';
}
_formKey.currentState.save();
return null;
},
onSaved: (String value) {
schooluser.username = value;
},
),
),
MyTextFormField(
hintText: 'New Password',
isPassword: true,
validator: (String value) {
if (value.length < 7) {
return 'Password should be at least 7 characters long';
} else if (schooluser.password != null) {
print(value);
print(schooluser.password);
}
return null;
},
onSaved: (String value) {
schooluser.password = value;
},
),
RaisedButton(
color: Colors.blueAccent,
onPressed: () {
if (_formKey.currentState.validate()) {
_formKey.currentState.save();
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ResultSchool(schooluser: this.schooluser)));
}
},
child: Text(
'Done',
style: TextStyle(
color: Colors.white,
),
),
)
],
),
),
),
);
}
}
class MyTextFormField extends StatelessWidget {
final String hintText;
final Function validator;
final Function onSaved;
final bool isPassword;
final bool isEmail;
MyTextFormField({
this.hintText,
this.validator,
this.onSaved,
this.isPassword = false,
this.isEmail = false,
});
#override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.all(8.0),
child: TextFormField(
decoration: InputDecoration(
hintText: hintText,
contentPadding: EdgeInsets.all(15.0),
border: InputBorder.none,
filled: true,
fillColor: Colors.grey[200],
),
obscureText: isPassword ? true : false,
validator: validator,
onSaved: onSaved,
keyboardType: isEmail ? TextInputType.emailAddress : TextInputType.text,
),
);
}
}
Here's the model.dart which has all the variables:-
import 'package:flutter/material.dart';
import 'package:instaskool/screens/school_code.dart';
class Model {
String fullname;
String code;
String standard;
String section;
String username;
String password;
Model({this.fullname, this.code, this.standard, this.section, this.username, this.password});
}
class School {
String schoolName;
String schoolPhone;
String schoolEmail;
String schoolWebsite;
School({this.schoolName, this.schoolPhone, this.schoolEmail, this.schoolWebsite});
}
class SchoolDet {
String addressOne;
String addressTwo;
String city;
String pincode;
String state;
SchoolDet({this.addressOne, this.addressTwo, this.city, this.pincode, this.state});
}
class SchoolUser{
String username;
String password;
SchoolUser({this.username, this.password});
}
class SchoolCode{
String principalCode;
String teacherCode;
String studentCode;
SchoolCode({this.principalCode, this.teacherCode, this.studentCode});
}
Here's the result screen where I wanna display all the data:-
import 'package:flutter/material.dart';
import 'package:instaskool/model.dart';
class ResultSchool extends StatelessWidget {
School school;
SchoolDet schooldet;
SchoolCode schoolcode;
SchoolUser schooluser;
ResultSchool({this.school, this.schooldet, this.schooluser});
#override
Widget build(BuildContext context) {
return (Scaffold(
appBar: AppBar(title: Text('School details')),
body: Container(
margin: EdgeInsets.all(10.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(school.schoolName, style: TextStyle(fontSize: 22)),
Text(school.schoolPhone, style: TextStyle(fontSize: 22)),
Text(school.schoolEmail, style: TextStyle(fontSize: 22)),
Text(school.schoolWebsite, style: TextStyle(fontSize: 22)),
Text(schooldet.addressOne, style: TextStyle(fontSize: 22)),
Text(schooldet.addressTwo, style: TextStyle(fontSize: 22)),
Text(schooldet.city, style: TextStyle(fontSize: 22)),
Text(schooldet.pincode, style: TextStyle(fontSize: 22)),
Text(schooldet.state, style: TextStyle(fontSize: 22)),
Text(schooluser.username, style: TextStyle(fontSize: 22)),
Text(schooluser.password, style: TextStyle(fontSize: 22)),
Text(schoolcode.teacherCode, style: TextStyle(fontSize: 22)),
Text(schoolcode.principalCode, style: TextStyle(fontSize: 22)),
],
),
),
));
}
}
Add a widget to manage form transitions
enum SchoolFormPhase { BASIC_DTL, ADDRESS, USER_DTL }
class SchoolRegistration extends StatefulWidget {
#override
_SchoolRegistrationState createState() => _SchoolRegistrationState();
}
class _SchoolRegistrationState extends State<SchoolRegistration> {
SchoolFormPhase phase;
School schoolForm;
#override
void initState() {
phase = SchoolFormPhase.BASIC_DTL;
schoolForm = School();
super.initState();
}
#override
Widget build(BuildContext context) {
switch (phase) {
case SchoolFormPhase.BASIC_DTL:
return SchoolReg(
school: schoolForm,
onSaved: (school) {
setState(() {
schoolForm = school;
phase = SchoolFormPhase.ADDRESS;
});
});
case SchoolFormPhase.ADDRESS:
return SchoolRegTwo(
school: schoolForm,
onSaved: (school) {
setState(() {
schoolForm = school;
phase = SchoolFormPhase.USER_DTL;
});
});
case SchoolFormPhase.USER_DTL:
return SchoolRegThree(
school: schoolForm,
onSaved: (school) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ResultSchool(
schooluser: school.user,
school: school,
schooldet: school.address)));
},
);
}
return Container();
}
}
change the Form widget to accept inputs
class SchoolReg extends StatefulWidget {
final School school;
final Function(School) onSaved;
const SchoolReg({Key key, this.school, this.onSaved}) : super(key: key);
#override
_SchoolRegState createState() => _SchoolRegState();
}
class _SchoolRegState extends State<SchoolReg> {
final _formKey = GlobalKey<FormState>();
School _school;
#override
void initState() {
_school = widget.school;
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: SingleChildScrollView(
child: new Form(
key: _formKey,
child: Column(children: <Widget>[
Container(
margin: EdgeInsets.only(top: 130),
alignment: Alignment.topCenter,
child: MyTextFormField(
hintText: 'School name',
validator: (String value) {
return value.isEmpty
? 'Enter your school name'
: null;
},
onSaved: (value) => _school.schoolName = value)),
MyTextFormField(
hintText: 'Phone',
validator: (String value) {
if (value.isEmpty) {
return 'Enter the phone number';
}
return null;
},
onSaved: (String value) {
_school.schoolPhone = value;
},
),
MyTextFormField(
hintText: 'Email',
validator: (String value) {
if (value.isEmpty) {
return 'Enter the email address';
}
return null;
},
onSaved: (String value) {
_school.schoolEmail = value;
},
),
MyTextFormField(
hintText: 'School Website',
isEmail: true,
validator: (String value) {
if (value.isEmpty) {
return "Enter the school's website";
}
return null;
},
onSaved: (String value) {
_school.schoolWebsite = value;
},
),
RaisedButton(
color: Colors.blueAccent,
onPressed: () {
if (_formKey.currentState.validate()) {
_formKey.currentState.save();
widget.onSaved(_school);
}
},
child:
Text('Next', style: TextStyle(color: Colors.white)))
]))));
}
}
form 2
class SchoolRegTwo extends StatefulWidget {
final School school;
final Function(School) onSaved;
const SchoolRegTwo({Key key, this.school, this.onSaved}) : super(key: key);
#override
_SchoolRegTwoState createState() => _SchoolRegTwoState();
}
class _SchoolRegTwoState extends State<SchoolRegTwo> {
final _formKey = GlobalKey<FormState>();
SchoolDet schooldet;
#override
void initState() {
schooldet = widget.school.address;
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: SingleChildScrollView(
child: new Form(
key: _formKey,
child: Column(children: <Widget>[
Container(
margin: EdgeInsets.only(top: 130),
alignment: Alignment.topCenter,
child: MyTextFormField(
hintText: 'School address 1',
validator: (String value) {
if (value.isEmpty) {
return "Enter your school's address";
}
return null;
},
onSaved: (String value) {
schooldet.addressOne = value;
},
),
),
MyTextFormField(
hintText: 'School address 2',
validator: (String value) {
if (value.isEmpty) {
return "Enter the school's address";
}
return null;
},
onSaved: (String value) {
schooldet.addressTwo = value;
},
),
MyTextFormField(
hintText: 'City',
validator: (String value) {
if (value.isEmpty) {
return 'Enter the city';
}
return null;
},
onSaved: (String value) {
schooldet.city = value;
},
),
MyTextFormField(
hintText: 'Pincode',
isEmail: true,
validator: (String value) {
if (value.isEmpty) {
return "Enter the pincode";
}
return null;
},
onSaved: (String value) {
schooldet.pincode = value;
},
),
MyTextFormField(
hintText: 'State',
isEmail: true,
validator: (String value) {
if (value.isEmpty) {
return "Enter the state";
}
return null;
},
onSaved: (String value) {
schooldet.state = value;
},
),
RaisedButton(
color: Colors.blueAccent,
onPressed: () {
if (_formKey.currentState.validate()) {
_formKey.currentState.save();
widget.school.address = schooldet;
widget.onSaved(widget.school);
}
},
child:
Text('Next', style: TextStyle(color: Colors.white)))
]))));
}
}
form 3
class SchoolRegThree extends StatefulWidget {
School school;
final Function(School) onSaved;
SchoolRegThree({this.school, this.onSaved});
#override
_SchoolRegThreeState createState() => _SchoolRegThreeState();
}
class _SchoolRegThreeState extends State<SchoolRegThree> {
final _formKey = GlobalKey<FormState>();
SchoolUser schooluser;
#override
void initState() {
schooluser = widget.school.user;
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: SingleChildScrollView(
child: new Form(
key: _formKey,
child: Column(children: <Widget>[
Container(
margin: EdgeInsets.only(top: 100),
child: MyTextFormField(
hintText: 'Username',
isPassword: true,
validator: (String value) {
if (value.length < 5) {
return 'Username should be at least 5 characters long';
}
_formKey.currentState.save();
return null;
},
onSaved: (String value) {
schooluser.username = value;
},
),
),
MyTextFormField(
hintText: 'New Password',
isPassword: true,
validator: (String value) {
if (value.length < 7) {
return 'Password should be at least 7 characters long';
} else if (schooluser.password != null) {
print(value);
print(schooluser.password);
}
return null;
},
onSaved: (String value) {
schooluser.password = value;
},
),
RaisedButton(
color: Colors.blueAccent,
onPressed: () {
if (_formKey.currentState.validate()) {
_formKey.currentState.save();
widget.school.user = schooluser;
widget.onSaved(widget.school);
}
},
child: Text('Done',
style: TextStyle(
color: Colors.white,
)))
]))));
}
}
and finally consolidate the model to a single model class
class School {
String schoolName;
String schoolPhone;
String schoolEmail;
String schoolWebsite;
SchoolDet address;
SchoolUser user;
}
class SchoolDet {
String addressOne;
String addressTwo;
String city;
String pincode;
String state;
}
class SchoolUser {
String username;
String password;
}
Best is to use a state management solution like flutter_bloc, provider, etc.
Store it in an array on a different file using state management.
Make the bloc/provider available to all the screens.
You can pass through constructor but I don't recommend that as it will be too messy.