flutter: not navigating to another page - flutter

what i am trying to get is when i type Id and password in the form i should be able to get into another page. But when i press submit , nothing is happening.The error i am getting is Equality operator == invocation with references of unrelated types. Is there any way to solve that?
Form(
key: _formKey,
child: Column(children: <Widget>[
TextFormField(
controller: nameController,
decoration: InputDecoration(labelText: 'Id'),
keyboardType: TextInputType.emailAddress,
validator: (value) {
if (value.isEmpty) {
return 'Enter id';
}
return null;
},
),
TextFormField(
controller: passwordController,
decoration: InputDecoration(labelText: 'Password'),
obscureText: true,
validator: (value) {
if (value.isEmpty) {
return 'invalid password';
}
return null;
},
),
SizedBox(height: 30),
RaisedButton(
child: Text('Submit'),
onPressed: () {
if (nameController == //i am getting a blue underline over here
FirebaseFirestore.instance
.collection("proddecAdmin")
.doc("1")
.set({'Id': ''}) &&
passwordController == //i am getting a blue underline over here
FirebaseFirestore.instance
.collection("proddecAdmin")
.doc("1")
.set({
'password': '',
})) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ProfilePage()),
);
}
},

nameController & password controller are just the TextEditingController instances. You want to compare against the value stored in the controllers. e.g.
nameController.value.text == ''
passwordController.value.text == ''

Related

How to match password and confirm password with Firebase in Flutter?

Use TextFormField widget which consists of a builtin validator
This code is only for valid without firebase validation but with firebase validation it can store data on database even both password and confirm Password cannot match?
Here I will give my code
void _submitForm() async {
final isValid = _formKey.currentState!.validate();
FocusScope.of(context).unfocus();
var date = DateTime.now().toString();
var dateparse = DateTime.parse(date);
var formattedDate = "${dateparse.day}-${dateparse.month}-${dateparse.year}";
if (isValid) {
_formKey.currentState!.save();
try {
setState(() {
_isLoading = true;
});
await _auth.createUserWithEmailAndPassword(
email: _emailAddress.text, password: _passwordController.text);
final User? user = _auth.currentUser;
final _uid = user!.uid;
user.reload();
await FirebaseFirestore.instance.collection('users').doc(_uid).set({
'id': _uid,
'username': _username,
'email': _emailAddress,
'joinedAt': formattedDate,
'createdAt': Timestamp.now(),
'Password': _passwordController.text,
});
Navigator.of(context)
.push(MaterialPageRoute(builder: (context) => const SignInPage()));
} catch (error) {
_globalMethods.authErrorHandle(error.toString(), context);
print('error occured ${error.toString()}');
} finally {
setState(() {
_isLoading = false;
});
}
}
}
TextFormField of both Password and Confirm Password
Container(
padding: const EdgeInsets.only(right: 42),
child: TextFormField(
controller: _passwordController,
key: const ValueKey('Password'),
validator: (value) {
if (value!.isEmpty || value.length < 7) {
return 'Please enter a valid Password';
}
return null;
},
keyboardType: TextInputType.emailAddress,
focusNode: _passwordFocusNode,
autovalidateMode: AutovalidateMode.onUserInteraction,
decoration: const InputDecoration(
hintText: 'Password',
icon: Image(
image:
AssetImage('assets/images/Icon feather-lock.png'),
),
labelText: 'Password',
),
onSaved: (value) {
_passwordController.text = value!;
},
onEditingComplete: () => FocusScope.of(context)
.requestFocus(_confirmPasswordFocusNode),
),
),
const SizedBox(
height: 20,
),
Container(
padding: const EdgeInsets.only(right: 42),
child: TextFormField(
controller: _confirmPasswordController,
key: const ValueKey('Password'),
validator: (value) {
if (value!.isEmpty || value.length < 7) {
return 'Please enter a valid Password';
}
return null;
},
keyboardType: TextInputType.emailAddress,
focusNode: _confirmPasswordFocusNode,
autovalidateMode: AutovalidateMode.onUserInteraction,
onEditingComplete: _submitForm,
decoration: const InputDecoration(
hintText: 'Confirm Password',
icon: Image(
image: AssetImage(
'assets/images/Icon feather-lock.png'),
),
),
onSaved: (value) {
_confirmPasswordController.text = value!;
}),
),
Use this to match your password and conformPassword
if (conformPassword != password) {
return 'password is not matched'
}

how can i solve blocProvider context problem?

I have submit button, but when i press the button it gives this error:
BlocProvider.of() called with a context that does not contain a
CreatePostCubit.
No ancestor could be found starting from the
context that was passed to BlocProvider.of(). This
can happen if the context you used comes from a widget above the
BlocProvider.
The context used was: Builder
I suppose contexts get mixed. how can i solve this error?
my code:
Widget createPostButton(BuildContext context) {
final TextEditingController _postTitleController = TextEditingController();
final TextEditingController _postDetailsController = TextEditingController();
final TextEditingController _priceController = TextEditingController();
final _formKey = GlobalKey<FormState>(debugLabel: '_formKey');
return BlocProvider<CreatePostCubit>(
create: (context) => CreatePostCubit(),
child: Padding(
padding: const EdgeInsets.only(right: 13.0, bottom: 13.0),
child: FloatingActionButton(
child: FaIcon(FontAwesomeIcons.plus),
onPressed: () {
showDialog(
context: context,
barrierDismissible: false,
builder: (context) {
return AlertDialog(
content: Form(
key: _formKey,
child: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Padding(
padding: EdgeInsets.all(8.0),
child: TextFormField(
autocorrect: true,
controller: _postTitleController,
textCapitalization: TextCapitalization.words,
enableSuggestions: false,
validator: (value) {
if (value.isEmpty || value.length <= 4) {
return 'Please enter at least 4 characters';
} else {
return null;
}
},
decoration:
InputDecoration(labelText: 'Post Title'),
)),
Padding(
padding: EdgeInsets.all(8.0),
child: TextFormField(
controller: _postDetailsController,
autocorrect: true,
textCapitalization: TextCapitalization.words,
enableSuggestions: false,
validator: (value) {
if (value.isEmpty || value.length <= 25) {
return 'Please enter at least 25 characters';
} else {
return null;
}
},
decoration: InputDecoration(
labelText: 'Write a post details'),
)),
Padding(
padding: EdgeInsets.all(8.0),
child: TextFormField(
controller: _priceController,
enableSuggestions: false,
inputFormatters: <TextInputFormatter>[
FilteringTextInputFormatter.digitsOnly
],
keyboardType: TextInputType.number,
validator: (value) {
if (value.isEmpty || value.length >= 4) {
return 'Please enter a valid value';
} else {
return null;
}
},
decoration:
InputDecoration(labelText: 'Enter the Price'),
)),
OutlinedButton(
style: OutlinedButton.styleFrom(
primary: Colors.white,
backgroundColor: Colors.blue,
),
child: Text("Submit"),
onPressed: () => {
BlocProvider.of<CreatePostCubit>(context)
.createNewPost(
postTitle: _postTitleController.text,
postDetails: _postDetailsController.text,
price: _priceController.text)
},
),
],
),
),
),
);
});
},
),
),
);
}
Your showDialog builder is using new context. The widget returned by the builder does not share a context with the location that showDialog is originally called from.
Just rename builder parameter into something else
showDialog(
context: context,
barrierDismissible: false,
builder: (dialog_context) { // instead of context
return AlertDialog(
....
Also you need to wrap BlocProvide child with builder(so it can access inherited BlocProvider)
BlocProvider<CreatePostCubit>(
create: (context) => CreatePostCubit(),
child: Builder(
builder: (BuildContext context) => Padding(
...
Use BlocProvider.of<CreatePostCubit>(context,listen:false) instead of BlocProvider.of<CreatePostCubit>(context) in you submit button.
I think the problem is that context in
BlocProvider.of<CreatePostCubit>(context) refer to the orginal context which doesn't have cubit so try to rename the context into sth else like _context :
create: (_context) => CreatePostCubit(),
and when calling like this
BlocProvider.of<CreatePostCubit>(_context)

Flutter Web submit form on enter key

Is there a way to call the submit button when a user hits the enter button when filling out a form. Here is my form code:
#override
Widget build(BuildContext context) {
String _email;
return AlertDialog(
title: Text('Password Reset'),
content: Form(
key: _formKey,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
TextFormField(
decoration: InputDecoration(
hintText: 'Email',
labelText: 'Email',
),
autofocus: true,
maxLength: 30,
validator: (value) {
if (value.isEmpty) {
return 'Email is required';
}
return null;
},
onSaved: (input) => _email = input,
),
],
),
),
actions: [
RaisedButton(
onPressed: () async {
if (_formKey.currentState.validate()) {
_formKey.currentState.save();
var result = await auth.sendPasswordResetEmail(_email);
print(result);
Navigator.of(context).pop();
}
},
child: Text('Reset'),
)
],
);
}
For a TextFormField the property to handle this would be onFieldSubmitted. You can copy the code from your onPressed of the RaiseButton to this. For e.g.
onFieldSubmitted: (value) {
if (_formKey.currentState.validate()) {
_formKey.currentState.save();
// var result = await auth.sendPasswordResetEmail(_email);
// print(result);
print(_email);
Navigator.of(context).pop();
}
},
A full example is available as a codepen here.
You might be interested in RawKeyboardListener as well however it
doesn't recognize the enter key. But could listen to other keys such as Shift, CapsLock etc.
Use either the onEditingComplete or onSubmitted parameters of the TextFormField constructor, depending on your needs.
Check that the TextFormField has the textInputAction set to TextInputAction.done or TextInputAction.go

Flutter: Best way to get all values in a form

I'm making a data collection app which has multiple TextFields, like more than 12. I'm using a Form key to validate all of them. I want values of all the text fields so I can save them to firestore. How do I do this? Here's my code:
import 'package:flutter/material.dart';
class MainForm extends StatefulWidget {
#override
_MainFormState createState() => _MainFormState();
}
class _MainFormState extends State<MainForm> {
final _formKey = GlobalKey<FormState>();
#override
Widget build(BuildContext context) {
return Center(
child: SingleChildScrollView(
child: Form(
key: _formKey,
child: Column(
children: <Widget>[
Text('Enter information about PG Owner'),
Padding(
padding: const EdgeInsets.all(8.0),
child: TextField(
autofocus: true,
textCapitalization: TextCapitalization.words,
textAlignVertical: TextAlignVertical.center,
onTap: () {},
decoration: InputDecoration(
prefixIcon: Icon(Icons.face),
labelText: 'Enter Name of Owner',
border: OutlineInputBorder()),
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: TextFormField(
validator: (value) {
if (value.length < 15) {
return 'Address seems very short!';
}
return null;
},
keyboardType: TextInputType.text,
decoration: InputDecoration(
prefixIcon: Icon(Icons.room),
labelText: 'Enter full address of Owner',
border: OutlineInputBorder()),
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: TextFormField(
keyboardType: TextInputType.number,
validator: (value) {
if (value.length < 9) {
return 'Phone number must be 9 digits or longer';
}
return null;
},
decoration: InputDecoration(
prefixIcon: Icon(Icons.phone),
labelText: 'Phone number of Owner',
border: OutlineInputBorder()),
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: TextFormField(
validator: (value) {
if (value.isEmpty) {
return 'Please enter a valid email address';
}
if (!value.contains('#')) {
return 'Email is invalid, must contain #';
}
if (!value.contains('.')) {
return 'Email is invalid, must contain .';
}
return null;
},
keyboardType: TextInputType.emailAddress,
decoration: InputDecoration(
prefixIcon: Icon(Icons.mail_outline),
labelText: 'Enter Email',
border: OutlineInputBorder()),
),
),
)
],
),
),
),
);
}
}
Update: I know that proper way (I've read the docs) of getting values from a TextField is by creating a controller. But, In my case there are 14 TextFields which requires me to create 14 controllers. Is there a better way of doing this?
You can use something like this in the following code:
_formKey.currentState.save(); calls the onSaved() on each textFormField items, which assigns the value to all the fields and you can use them as required. Try using the _formKey.currentState.save(); just after _formKey.currentState.validate() is evaluated as true.
The form code looks like this:
String contactNumber;
String pin;
return Form(
key: _formKey,
child: Column(
children: <Widget>[
TextFormField(
onSaved: (String value){contactNumber=value;},
keyboardType: TextInputType.phone,
inputFormatters: [WhitelistingTextInputFormatter.digitsOnly],
maxLength: 10,
decoration: InputDecoration(
labelText: "Enter Your Mobile Number",
hintText: "Number",
icon: Icon(Icons.phone_iphone)),
validator: (value) {
if (value.isEmpty || value.length < 10) {
return 'Please Enter 10 digit number';
}
return null;
},
),
TextFormField(
onSaved: (String value){pin=value;},
keyboardType: TextInputType.phone,
inputFormatters: [WhitelistingTextInputFormatter.digitsOnly],
maxLength: 10,
decoration: InputDecoration(
labelText: "Enter Your PIN",
hintText: "Number",
icon: Icon(Icons.lock)),
validator: (value) {
if (value.isEmpty || value.length < 6) {
return 'Please Enter 6 digit PIN';
}
return null;
},
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 16.0),
child: RaisedButton(
color: Colors.black,
textColor: Colors.white,
onPressed: () {
if (_formKey.currentState.validate()) {
***_formKey.currentState.save();***
bloc.loginUser(contactNumber, pin);
}
},
child: Text('Login' /*style: TextStyle(fontSize: 30),*/)),
)
],
),
);
Using controller in TextFormField, you can get value of the TextFormField.
TextEditingController emailEditingController = TextEditingController();
TextFormField(
controller: emailEditingController,
validator: (value) {
if (value.isEmpty) {
return 'Please enter a valid email address';
}
if (!value.contains('#')) {
return 'Email is invalid, must contain #';
}
if (!value.contains('.')) {
return 'Email is invalid, must contain .';
}
return null;
},
keyboardType: TextInputType.emailAddress,
decoration: InputDecoration(
prefixIcon: Icon(Icons.mail_outline),
labelText: 'Enter Email',
border: OutlineInputBorder()),
);
Get Value like:
String email=emailEditingController.text;
Updated Answer
Get value by using onSubmitted
onSubmitted: (String value){email=value;},
I am not satisfied with how Flutter make you handle the form values yourself, you need to create a TextEditingController instance for each field, assign it to the controller and remember to dispose all of them manually. This leads to a lot of boilerplate code and makes it more error-prone:
final _formKey = GlobalKey<FormState>();
final controller1 = TextEditingController();
final controller2 = TextEditingController();
final controller3 = TextEditingController();
#override
void dispose() {
super.dispose();
controller1.dispose();
controller2.dispose();
controller3.dispose();
}
#override
Widget build(BuildContext context) {
return Form(
key: _formKey,
child: Column(children: [
TextFormField(controller: controller1),
TextFormField(controller: controller2),
TextFormField(
controller: controller3,
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please enter some text';
}
return null;
},
),
ElevatedButton(
onPressed: () {
if (_formKey.currentState!.validate()) {
final value1 = controller1.text;
final value2 = controller2.text;
final value3 = controller3.text;
// do something with the form data
}
},
child: const Text('Submit'),
),
]),
);
}
A much less cumbersome way is to use the flutter_form_builder package and replace TextFormField with the FormBuilderTextField widget which is a wrapper of the old plain TextField. You can see all of the supported input widgets here.
All you need to do now is to specify the name of each field in your form, and access it in _formKey.currentState?.value. See the example below:
final _formKey = GlobalKey<FormBuilderState>();
#override
Widget build(BuildContext context) {
return FormBuilder(
key: _formKey,
child: Column(children: [
FormBuilderTextField(name: 'field1'),
FormBuilderTextField(name: 'field2'),
FormBuilderTextField(
name: 'field3',
validator: FormBuilderValidators.required(
context,
errorText: 'Please enter some text',
),
),
ElevatedButton(
onPressed: () {
_formKey.currentState.save();
if (_formKey.currentState!.validate()) {
final formData = _formKey.currentState?.value;
// formData = { 'field1': ..., 'field2': ..., 'field3': ... }
// do something with the form data
}
},
child: const Text('Submit'),
),
]),
);
}
You can use flutter_form_bloc, you don't need to create any TextEditingController and can separate the Business Logic from the User Interface, in addition to offering other advantages.
dependencies:
flutter_bloc: ^0.21.0
form_bloc: ^0.4.1
flutter_form_bloc: ^0.3.0
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_form_bloc/flutter_form_bloc.dart';
import 'package:form_bloc/form_bloc.dart';
void main() => runApp(MaterialApp(home: MainForm()));
class MainFormBloc extends FormBloc<String, String> {
final nameField = TextFieldBloc();
final addressField = TextFieldBloc(validators: [
(value) => value.length < 15 ? 'Address seems very short!' : null,
]);
final phoneNumberField = TextFieldBloc(validators: [
(value) =>
value.length < 9 ? 'Phone number must be 9 digits or longer' : null,
]);
final emailField = TextFieldBloc(validators: [Validators.email]);
#override
List<FieldBloc> get fieldBlocs => [
nameField,
addressField,
phoneNumberField,
emailField,
];
#override
Stream<FormBlocState<String, String>> onSubmitting() async* {
// This method is called when you call [mainFormBloc.submit]
// and each field bloc have a valid value.
// And you can save them in firestore.
print(nameField.value);
print(addressField.value);
print(phoneNumberField.value);
print(emailField.value);
yield currentState.toSuccess('Data saved successfully.');
// yield `currentState.toLoaded()` because
// you can't submit if the state is `FormBlocSuccess`.
// In most cases you don't need to do this,
// because you only want to submit only once.
yield currentState.toLoaded();
}
}
class MainForm extends StatelessWidget {
#override
Widget build(BuildContext context) {
return BlocProvider<MainFormBloc>(
builder: (context) => MainFormBloc(),
child: Builder(
builder: (context) {
final formBloc = BlocProvider.of<MainFormBloc>(context);
return Scaffold(
appBar: AppBar(title: Text('Main Form')),
body: FormBlocListener<MainFormBloc, String, String>(
onSuccess: (context, state) {
Scaffold.of(context).showSnackBar(
SnackBar(
content: Text(state.successResponse),
backgroundColor: Colors.green,
),
);
},
onSubmissionFailed: (context, state) {
Scaffold.of(context).showSnackBar(
SnackBar(
content: Text('Some fields have invalid data.'),
backgroundColor: Colors.red,
),
);
},
child: ListView(
children: <Widget>[
TextFieldBlocBuilder(
textFieldBloc: formBloc.nameField,
padding: const EdgeInsets.all(8.0),
autofocus: true,
textCapitalization: TextCapitalization.words,
textAlignVertical: TextAlignVertical.center,
decoration: InputDecoration(
prefixIcon: Icon(Icons.face),
labelText: 'Enter Name of Owner',
border: OutlineInputBorder()),
),
TextFieldBlocBuilder(
textFieldBloc: formBloc.addressField,
padding: const EdgeInsets.all(8.0),
keyboardType: TextInputType.text,
decoration: InputDecoration(
prefixIcon: Icon(Icons.room),
labelText: 'Enter full address of Owner',
border: OutlineInputBorder()),
),
TextFieldBlocBuilder(
textFieldBloc: formBloc.phoneNumberField,
padding: const EdgeInsets.all(8.0),
keyboardType: TextInputType.number,
decoration: InputDecoration(
prefixIcon: Icon(Icons.phone),
labelText: 'Phone number of Owner',
border: OutlineInputBorder()),
),
TextFieldBlocBuilder(
textFieldBloc: formBloc.emailField,
padding: const EdgeInsets.all(8.0),
keyboardType: TextInputType.emailAddress,
decoration: InputDecoration(
prefixIcon: Icon(Icons.mail_outline),
labelText: 'Enter Email',
border: OutlineInputBorder()),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: RaisedButton(
onPressed: formBloc.submit,
child: Center(child: Text('SUBMIT')),
),
),
],
),
),
);
},
),
);
}
}
I came here from a similar search. All the answers found did not satisfy my need, hence I wrote a custom solution.
form key
final _signUpKey = GlobalKey<FormState>();
declare your TextEditingController
final Map<String, TextEditingController> sigUpController = {
'firstName': TextEditingController(),
'lastName': TextEditingController(),
'email': TextEditingController(),
'phone': TextEditingController(),
'password': TextEditingController(),
};
Pass controller to TextFormField like this
Form(
key: _signUpKey,
child: Column(
children: [
TextFormField(
controller: sigUpController['firstName'],
validator: validator,
autofocus: autofocus,
keyboardType: TextInputType.text,
style: const TextStyle(
fontSize: 14,
),
onTap: onTap,
onChanged: onChanged,
inputFormatters: [
FilteringTextInputFormatter.allow(
RegExp(r"[a-zA-Z]+|\s"),
),
],
),
// define the other TextFormField here
TextButton(
onPressed: () {
if (!_signUpKey.currentState!.validate()) {
return;
}
// To get data I wrote an extension method bellow
final data = sigUpController.data();
print('data: $data'); // data: {firstName: John, lastName: Doe, email: example#email.com, phone: 0000000000, password: password}
},
child: const Text('submit'),
)
],
),
);
Extension method to get data from Map<String, TextEditingController>
extension Data on Map<String, TextEditingController> {
Map<String, dynamic> data() {
final res = <String, dynamic>{};
for (MapEntry e in entries) {
res.putIfAbsent(e.key, () => e.value?.text);
}
return res;
}
}
Try using this flutter package flutter_form_builder, it will help you from repeating yourself by creating multiple controllers for each form field. In addition to that, it will help you in validating the form, and updating the form with simplicity by using only a simple form key to control the entire form.

Flutter redirects on textFormField open

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');
},
);
}