Flutter redirects on textFormField open - flutter

whenever i click on the textFormField the keyboard opens and closes almost immediately i think it kinda refreshes the page. i have another page with a form where i dont face this problem.
here is the code for that page, the other form i have in the app is almost identical to this one
import 'package:flutter/material.dart';
import 'package:scoped_model/scoped_model.dart';
import '../scoped_models/products.dart';
class ProductAdd extends StatelessWidget {
final _formData = {
'title': null,
'description': null,
'price': null,
'image': 'assets/food.jpg'
};
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
Widget _titleField() {
return TextFormField(
decoration: InputDecoration(labelText: 'Enter Title'),
keyboardType: TextInputType.text,
validator: (String value) {
if (value.isEmpty) {
return 'Please enter a valid title';
}
},
onSaved: (value) {
print(value);
_formData['title'] = value;
},
);
}
Widget _descriptionField() {
return TextFormField(
decoration: InputDecoration(labelText: 'Enter Description'),
keyboardType: TextInputType.text,
validator: (String value) {
if (value.isEmpty) {
return 'Please enter a valid description';
}
},
onSaved: (value) {
print(value);
_formData['description'] = value;
},
);
}
Widget _priceField() {
return TextFormField(
decoration: InputDecoration(labelText: 'Enter Price'),
keyboardType: TextInputType.number,
validator: (String value) {
if (value.isEmpty) {
return 'Please enter a valid price';
}
},
onSaved: (value) {
print(value);
_formData['price'] = value;
},
);
}
Widget _submitButton(context) {
return RaisedButton(
textColor: Colors.white,
child: Text('LOGIN'),
onPressed: () {
if (!_formKey.currentState.validate()) {
return;
}
_formKey.currentState.save();
Navigator.pushReplacementNamed(context, '/products');
},
);
}
#override
Widget build(BuildContext context) {
return ScopedModelDescendant<ProductsModel>(
builder: (context, child, ProductsModel model) {
return Container(
child: Center(
child: Container(
child: SingleChildScrollView(
child: Container(
padding: EdgeInsets.all(20.0),
child: Form(
key: _formKey,
child: Column(
children: <Widget>[
_titleField(),
_descriptionField(),
_priceField(),
SizedBox(
height: 10.0,
),
_submitButton(context)
],
),
),
),
),
),
),
);
},
);
}
}
i'm using flutter version: 1.0.0

I was not able to reproduce the issue. I re-created your case and the keyboard worked just fine. I although skipped the scoped-model part of your code because I don't know how your setup is. But with minimal code, I couldn't replicate it. See below:
import 'package:flutter/material.dart';
import 'package:scoped_model/scoped_model.dart';
//import '../scoped_models/products.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: ProductAdd(),
);
}
}
class ProductAdd extends StatelessWidget {
final _formData = {
'title': null,
'description': null,
'price': null,
'image': 'assets/food.jpg'
};
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
Widget _titleField() {
return TextFormField(
decoration: InputDecoration(labelText: 'Enter Title'),
keyboardType: TextInputType.text,
validator: (String value) {
if (value.isEmpty) {
return 'Please enter a valid title';
}
},
onSaved: (value) {
print(value);
_formData['title'] = value;
},
);
}
Widget _descriptionField() {
return TextFormField(
decoration: InputDecoration(labelText: 'Enter Description'),
keyboardType: TextInputType.text,
validator: (String value) {
if (value.isEmpty) {
return 'Please enter a valid description';
}
},
onSaved: (value) {
print(value);
_formData['description'] = value;
},
);
}
Widget _priceField() {
return TextFormField(
decoration: InputDecoration(labelText: 'Enter Price'),
keyboardType: TextInputType.number,
validator: (String value) {
if (value.isEmpty) {
return 'Please enter a valid price';
}
},
onSaved: (value) {
print(value);
_formData['price'] = value;
},
);
}
Widget _submitButton(context) {
return RaisedButton(
textColor: Colors.white,
child: Text('LOGIN'),
onPressed: () {
if (!_formKey.currentState.validate()) {
return;
}
_formKey.currentState.save();
Navigator.pushReplacementNamed(context, '/products');
},
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Container(
child: SingleChildScrollView(
child: Container(
padding: EdgeInsets.all(20.0),
child: Form(
key: _formKey,
child: Column(
children: <Widget>[
_titleField(),
_descriptionField(),
_priceField(),
SizedBox(
height: 10.0,
),
_submitButton(context)
],
),
),
),
),
),
),
);
}
}
My Flutter version: 0.11.10

this is my correction, hope it works; u need to add TextEditingController titlecontroller froeach TextFormField,dont use onsaved() ; and on the submitbutton funtion use this :
TextEditingController _pricecontroller;
Widget _priceField() {
return TextFormField(
//addcontroller;
controller : __pricecontroller
decoration: InputDecoration(labelText: 'Enter Price'),
keyboardType: TextInputType.number,
validator: (String value) {
if (value.isEmpty) {
return 'Please enter a valid price';
}
},
onSaved: (value) {
print(value);
_formData['price'] = value;
},
);
}
Widget _submitButton(context) {
return RaisedButton(
textColor: Colors.white,
child: Text('LOGIN'),
onPressed: () {
if (!_formKey.currentState.validate()) {
_formKey.currentState.save();
_formData['title'] = __titlecontroller.text;
_formData['description'] = __desccontroller.text;
_formData['price'] = __pricecontroller.text;
}
Navigator.pushReplacementNamed(context, '/products');
},
);
}

Related

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.

My forms widget is not scrolling. How to define the size of the forms widget in flutter, complete form is not shown or visible

My forms widget is not scrolling. How to define the size of the forms widget in flutter, complete form is not shown or visible. The user has to enter the following data / information and submit
folowing is my code `
class MiMobilesPageState extends State<MiMobilesPage> {
String _companyname;
String _modelname;
String _series;
String _year;
String _serielnumber;
String _warrantydate;
String _servicecentredetails;
String _name;
String _mobilenumber;
String _address;
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
Widget _buildCompanyName() {
return TextFormField(
decoration: InputDecoration(labelText: 'CompanyName'),
maxLength: 10,
validator: (String value) {
if (value.isEmpty) {
return 'Company Name is Required';
}
return null;
},
onSaved: (String value) {
_companyname = value;
},
);
}
Widget _buildModelName() {
return TextFormField(
decoration: InputDecoration(labelText: 'ModelName'),
validator: (String value) {
if (value.isEmpty) {
return 'Model Name';
}
},
onSaved: (String value) {
_modelname = value;
},
);
}
Widget _buildSeries() {
return TextFormField(
decoration: InputDecoration(labelText: 'Series'),
keyboardType: TextInputType.visiblePassword,
validator: (String value) {
if (value.isEmpty) {
return 'Series is Required';
}
return null;
},
onSaved: (String value) {
_series = value;
},
);
}
Widget _buildYear() {
return TextFormField(
decoration: InputDecoration(labelText: 'Year'),
keyboardType: TextInputType.url,
validator: (String value) {
if (value.isEmpty) {
return 'Year of MFG is Required';
}
return null;
},
onSaved: (String value) {
_year = value;
},
);
}
Widget _buildSerielNumber() {
return TextFormField(
decoration: InputDecoration(labelText: 'SerielNumber'),
keyboardType: TextInputType.phone,
maxLength: 20,
validator: (String value) {
if (value.isEmpty) {
return 'Seriel-Number is Required';
}
return null;
},
onSaved: (String value) {
_serielnumber = value;
},
);
}
Widget _buildWarrantyDate() {
return TextFormField(
decoration: InputDecoration(labelText: 'Warranty-Date'),
keyboardType: TextInputType.number,
maxLength: 10,
validator: (String value) {
int date = int.tryParse(value);
if (date == null || date <= 0) {
return 'Warranty Date must be greater than 0';
}
return null;
},
onSaved: (String value) {
_warrantydate = value;
},
);
}
Widget _buildServiceCentreDetails() {
return TextFormField(
decoration: InputDecoration(labelText: 'ServiceCentreDetails'),
maxLength: 10,
validator: (String value) {
if (value.isEmpty) {
return 'Service Centre Details are Required';
}
return null;
},
onSaved: (String value) {
_servicecentredetails = value;
},
);
}
Widget _buildName() {
return TextFormField(
decoration: InputDecoration(labelText: 'Name'),
maxLength: 10,
validator: (String value) {
if (value.isEmpty) {
return 'Name is Required';
}
return null;
},
onSaved: (String value) {
_name = value;
},
);
}
Widget _buildMobileNumber() {
return TextFormField(
decoration: InputDecoration(labelText: 'MobileNumber'),
maxLength: 10,
validator: (String value) {
if (value.isEmpty) {
return 'Mobile Number is Required';
}
return null;
},
onSaved: (String value) {
_mobilenumber = value;
},
);
}
Widget _buildAddress() {
return TextFormField(
decoration: InputDecoration(labelText: 'Address'),
maxLength: 10,
validator: (String value) {
if (value.isEmpty) {
return 'Address is Required';
}
if (!RegExp(
r"[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*#(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?")
.hasMatch(value)) {
return 'Please enter a valid Address';
}
return null;
},
onSaved: (String value) {
_companyname = value;
},
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(centerTitle: true,backgroundColor: Colors.lightBlueAccent,title: Text("Basic Details",style:
TextStyle(fontSize: 20), textAlign: TextAlign.center),
actions:<Widget>[IconButton(icon:Icon(Icons.home), onPressed: (){
//debugPrint("Add New Device Cattegorry");
Navigator.push(context,MaterialPageRoute(builder:(context){
return MyHomePage();
}
)
); //
},
) ],
),
body: Container(
margin: EdgeInsets.all(24),
child: Form(
key: _formKey,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget> [
_buildCompanyName(),
_buildModelName(),
_buildSeries(),
_buildYear(),
_buildSerielNumber(),
_buildWarrantyDate(),
_buildServiceCentreDetails(),
_buildName(),
_buildMobileNumber(),
_buildAddress(),
SizedBox(height:400),
RaisedButton(
child: Text(
'Submit',
style: TextStyle(color: Colors.blue, fontSize: 20),
),
onPressed: () {
if (!_formKey.currentState.validate()) {
return;
}
_formKey.currentState.save();
print(_companyname);
print(_modelname);
print(_series);
print(_year);
print(_serielnumber);
print(_warrantydate);
print(_servicecentredetails);
print(_name);
print(_mobilenumber);
print(_address);
//Send to API
},
)
],
),
),
),
);
}
}
Please guide where I am wrong what is to be included in the code and what changes have to be made?`
I'm assuming the SizedBox(height:400), was a typo, meant to be 40?
To make your Form scroll, you'll need to wrap it in a Scrollable widget usually a ListView or a SingleChildScrollView.
I added an example using your code:
body: SingleChildScrollView( // wrap with SingleChildScrollView to allow scrolls
child: Container(
margin: EdgeInsets.all(24),
child: Form(
// key: _formKey,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
_buildCompanyName(),
_buildModelName(),
_buildSeries(),
_buildYear(),
_buildSerielNumber(),
_buildWarrantyDate(),
_buildServiceCentreDetails(),
_buildName(),
_buildMobileNumber(),
_buildAddress(),
SizedBox(height:400), // incase this is not an error as I assumed, change to 400
RaisedButton(
child: Text(
'Submit',
style: TextStyle(color: Colors.blue, fontSize: 20),
),
onPressed: () {
if (!_formKey.currentState.validate()) {
return;
}
_formKey.currentState.save();
print(_companyname);
print(_modelname);
print(_series);
print(_year);
print(_serielnumber);
print(_warrantydate);
print(_servicecentredetails);
print(_name);
print(_mobilenumber);
print(_address);
//Send to API
},
)
],
),
),
),
);
Wrap the Column in a SingleChildScrollView if you want it to scroll.
Like this
Form(
child: SingleChildScrollView(
child: Column(
children: [...]
)
)
)

TextFormField cursor did not move when changes occur

I have a screen that shows a textformfield, I want to retrieve the value that the user has inputted. But when I made a change the cursor didn't move, so it stays at position 0. How do I solve this problem?
class ScreenFormArtikel extends StatefulWidget {
final String mode;
ScreenFormArtikel(this.mode);
#override
_ScreenFormArtikelState createState() => _ScreenFormArtikelState();
}
class _ScreenFormArtikelState extends State<ScreenFormArtikel> {
var _key = GlobalKey<FormState>();
var _titleController = TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Article'),
),
body: Container(
child: Form(
key: _key,
child: Column(
children: [
Consumer<ProviderArtikel>(
builder: (context, artikel, child) {
return TextFormField(
decoration: InputDecoration(
labelText: 'Title',
floatingLabelBehavior: FloatingLabelBehavior.always),
controller: _titleController,
validator: (value) {
if (value.isEmpty) {
return "Please fill this field";
}
return null;
},
onChanged: (value) {
_titleController.text = value;
},
);
},
),
RaisedButton(onPressed: () {}),
],
),
),
),
);
}
}
I have attached the sample video below
click here
Commenting the onChanged will do the work.
TextFormField(
decoration: InputDecoration(
labelText: 'Title',
floatingLabelBehavior: FloatingLabelBehavior.always),
controller: _titleController,
validator: (value) {
if (value.isEmpty) {
return "Please fill this field";
}
return null;
},
// onChanged: (value) {
// _titleController.text = value;
// },
),
Actually the _titleController.text is setting the text onChange, that's why cursor is moving to the first place.
And you don't have to explicitly do the onTextChange thing.

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.

Flutter provider, Right way to use GlobalKey<FormState> in Provider

I'm new at Provider package. and Just making demo app for learning purpose.
Here is my code of simple Form Widget.
1) RegistrationPage (Where my app is start)
class RegistrationPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text("Title"),
),
body: MultiProvider(providers: [
ChangeNotifierProvider<UserProfileProvider>.value(value: UserProfileProvider()),
ChangeNotifierProvider<RegiFormProvider>.value(value: RegiFormProvider()),
], child: AllRegistrationWidgets()),
);
}
}
class AllRegistrationWidgets extends StatelessWidget {
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
FocusScope.of(context).requestFocus(FocusNode());
},
child: Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Expanded(
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
SetProfilePicWidget(),
RegistrationForm(),
],
),
),
),
BottomSaveButtonWidget()
],
),
),
);
}
}
class BottomSaveButtonWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
final _userPicProvider =
Provider.of<UserProfileProvider>(context, listen: false);
final _formProvider =
Provider.of<RegiFormProvider>(context, listen: false);
return SafeArea(
bottom: true,
child: Container(
margin: EdgeInsets.all(15),
child: FloatingActionButton.extended(
heroTag: 'saveform',
icon: null,
label: Text('SUBMIT',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
)),
onPressed: () {
print(_userPicProvider.strImageFileName);
_formProvider.globalFormKey.currentState.validate();
print(_formProvider.firstName);
print(_formProvider.lastName);
},
)),
);
}
}
2) RegistrationForm
class RegistrationForm extends StatefulWidget {
#override
_RegistrationFormState createState() => _RegistrationFormState();
}
class _RegistrationFormState extends State<RegistrationForm> {
TextEditingController _editingControllerFname;
TextEditingController _editingControllerLname;
#override
void initState() {
_editingControllerFname = TextEditingController();
_editingControllerLname = TextEditingController();
super.initState();
}
#override
Widget build(BuildContext context) {
final formProvider = Provider.of<RegiFormProvider>(context);
return _setupOtherWidget(formProvider);
}
_setupOtherWidget(RegiFormProvider _formProvider) {
return Container(
padding: EdgeInsets.all(12),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
SizedBox(height: 20),
Text(
'Fields with (*) are required.',
style: TextStyle(fontStyle: FontStyle.italic),
textAlign: TextAlign.left,
),
SizedBox(height: 20),
_formSetup(_formProvider)
],
),
);
}
_formSetup(RegiFormProvider _formProvider) {
return Form(
key: _formProvider.globalFormKey,
child: Container(
child: Column(
children: <Widget>[
TextFormField(
controller: _editingControllerFname,
textCapitalization: TextCapitalization.sentences,
decoration: InputDecoration(
labelText: "First Name *",
hintText: "First Name *",
),
onSaved: (value) {},
validator: (String value) =>
_formProvider.validateFirstName(value)),
SizedBox(height: 15),
TextFormField(
controller: _editingControllerLname,
textCapitalization: TextCapitalization.sentences,
validator: (String value) =>
_formProvider.validateLastName(value),
onSaved: (value) {},
decoration: InputDecoration(
labelText: "Last Name *",
hintText: "Last Name *",
),
)
],
),
),
);
}
#override
void dispose() {
_editingControllerFname.dispose();
_editingControllerLname.dispose();
super.dispose();
}
}
3) RegiFormProvider
class RegiFormProvider with ChangeNotifier {
final GlobalKey<FormState> globalFormKey = GlobalKey<FormState>();
String _strFirstName;
String _strLasttName;
String get firstName => _strFirstName;
String get lastName => _strLasttName;
String validateFirstName(String value) {
if (value.trim().length == 0)
return 'Please enter first name';
else {
_strFirstName = value;
return null;
}
}
String validateLastName(String value) {
if (value.trim().length == 0)
return 'Please enter last name';
else {
_strLasttName = value;
return null;
}
}
}
Here you can see, RegiFormProvider is my first page where other is children widgets in widget tree. I'm using final GlobalKey<FormState> globalFormKey = GlobalKey<FormState>(); in the RegiFormProvider provider, Because I want to access this in the 1st RegistrationPage to check my firstName and lastName is valid or not.
I'm using a builder widget to get form level context like below , and then easily we can get the form instance by using that context. by this way we don't need global key anymore.
Form(
child: Builder(
builder: (ctx) {
return ListView(
padding: EdgeInsets.all(12),
children: <Widget>[
TextFormField(
decoration: InputDecoration(labelText: "Title"),
textInputAction: TextInputAction.next,
onFieldSubmitted: (_) => FocusScope.of(context).nextFocus(),
initialValue: formProduct.title,
validator: validateTitle,
onSaved: (value) {
formProduct.title = value;
},
),
TextFormField(
decoration: InputDecoration(labelText: "Price"),
textInputAction: TextInputAction.next,
onFieldSubmitted: (_) => FocusScope.of(context).nextFocus(),
initialValue: formProduct.price == null
? ""
: formProduct.price.toString(),
keyboardType: TextInputType.number,
validator: validatePrice,
onSaved: (value) {
formProduct.price = double.parse(value);
},
),
TextFormField(
decoration: InputDecoration(labelText: "Description"),
textInputAction: TextInputAction.next,
initialValue: formProduct.description,
maxLines: 3,
validator: validateDescription,
onFieldSubmitted: (_) => FocusScope.of(context).nextFocus(),
onSaved: (value) {
formProduct.description = value;
},
),
TextFormField(
decoration: InputDecoration(labelText: "Image Url"),
textInputAction: TextInputAction.done,
onFieldSubmitted: (_) => FocusScope.of(context).unfocus(),
initialValue: formProduct.imageUrl,
validator: validateImageUrl,
onSaved: (value) {
formProduct.imageUrl = value;
},
),
Padding(
padding: EdgeInsets.all(10),
child: FlatButton(
color: Colors.amberAccent,
onPressed: () {
if (Form.of(ctx).validate()) {
Form.of(ctx).save();
formProduct.id =
Random.secure().nextDouble().toString();
ProductsProvider provider =
Provider.of<ProductsProvider>(context,
listen: false);
editing
? provider.setProduct(formProduct)
: provider.addProduct(formProduct);
Router.back(context);
}
},
child: Text("Save"),
),
)
],
);
},
),
)
you can see the Form.of(ctx) gives us the current level form.