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
Related
I have a IntlPhoneWidget and a textfield widget inside of a stepper widget. When I press the continue button it only validates the intlphonewidget and not the textfield. Also how do I put in a custom validation message for each of the fields inside of the stepper if those fields are empty?
Here is my code-
#override
Widget build(BuildContext context) {
return Scaffold(
body: Form(
key: _formKey,
child: Stepper(
currentStep: _currentStepper,
onStepContinue: _continueStep,
steps: [
Step(
title: const Text('Enter your name and phone number'),
content: Column(
children: [
TextField(
controller: _displayNameTextFieldController,
),
IntlPhoneField(
decoration: const InputDecoration(
labelText: 'Phone Number',
),
onChanged: (phone) {
setState(() {
_phoneNumber = (phone.completeNumber).trim();
});
},
)
],
),
)
],
),
),
);
}
void _continueStep() {
if (_currentStepper == 0) {
_formKey.currentState?.validate();
}
}
This happened because the IntlPhoneField has built-in validator, but TextField doesn't, if you want to have validator for first field too , you need to use TextFormField instead and set the validator like this:
TextFormField(
controller: _displayNameTextFieldController,
validator: (value) {
if (value != null && value.isEmpty) {
return 'fill name field';
}
return null;
},
)
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 == ''
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.
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');
},
);
}
How can I pass the barcode value into the TextForField after it scans? The Barcode function passes the barcode value to the String barcode. It's the ListTile Object with the OnTap function defined as scan();
I want to pass that value back into the field immediately. I tried a setState() function but couldn't quite figure it out. Thanks.
import 'dart:async';
import 'package:barcode_scan/barcode_scan.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'ItemData.dart';
import 'homepage.dart';
import 'Barcode.dart';
import 'package:flutter/services.dart';
class CreateWidget extends StatefulWidget {
#override
CreateState createState() => CreateState();
}
Data newData = new Data();
class CreateState extends State<CreateWidget> {
final GlobalKey<FormState> _formKey = new GlobalKey<FormState>();
void submit() {
_formKey.currentState.save();
}
String barcode = "";
#override
Widget build(BuildContext context) {
// TODO: implement build
return Column(
children: <Widget>[
Flexible(
flex: 0,
child: Center(
child: Form(
key: this._formKey,
child: Flex(
direction: Axis.vertical,
children: <Widget>[
ListTile(
title: TextFormField (
initialValue: '',
decoration: new InputDecoration(
icon: new Icon(Icons.info),
hintText: "Title",
),
validator: (val) => val.isEmpty ? null : 'Not a valid Title',
onSaved: (val) => newData.title = val,
),
),
ListTile(
title: TextFormField(
initialValue: '',
decoration: new InputDecoration(
icon: new Icon(Icons.info),
hintText: "Location",
),
validator: (val) => val.isEmpty ? 'Location is required' : null,
onSaved: (val) => newData.location = val,
),
),
/////////////////////////////////////
This is the list tile where I want the action to happen.
ListTile(
title: TextFormField(
initialValue: '',
decoration: new InputDecoration(
icon: new Icon(Icons.info),
hintText: "Barcode",
),
validator: (val) => val.isEmpty ? 'Barcode is required' : null,
onSaved: (val) => newData.barcode = val,
),
trailing: new Icon(Icons.search),
onTap: () {
{scan();}
},
),
ListTile(
title: TextFormField(
initialValue: '',
decoration: new InputDecoration(
icon: new Icon(Icons.info),
hintText: "Type",
),
validator: (val) => val.isEmpty ? 'Type is required' : null,
onSaved: (val) => newData.type = val,
),
),
ListTile(
leading: Icon(Icons.access_time),
title: Text(_getDateNow()),
),
RaisedButton(
color: Colors.red,
textColor: Colors.white,
child: new Text('Create'),
onPressed: () {
submit();
createItem();
Navigator.pop(context, true);
},
),
],
),
),
),
)
],
);
}
Future scan() async {
try {
String barcode = await BarcodeScanner.scan();
setState(() => this.barcode = barcode);
} on PlatformException catch (e) {
if (e.code == BarcodeScanner.CameraAccessDenied) {
setState(() {
this.barcode = 'The user did not grant the camera permission!';
});
} else {
setState(() => this.barcode = 'Unknown error: $e');
}
} on FormatException{
setState(() => this.barcode = 'null (User returned using the "back"-button before scanning anything. Result)');
} catch (e) {
setState(() => this.barcode = 'Unknown error: $e');
}
}
}
Future createItem() async {
Firestore.instance.runTransaction((Transaction transaction) async {
CollectionReference reference =
Firestore.instance.collection('items');
await reference.add({"title": newData.title, "location": newData.location, "type": newData.type,"date": _getDateNow(), "editing": false, "barcode": newData.barcode,});
});
}
_getDateNow() {
var now = new DateTime.now();
var formatter = new DateFormat('MM-dd-yyyy H:mm');
return formatter.format(now);
}
For the Text From Field Make a controller where you initialised the String barcode as follows :-
TextEditingContoller c = new TextEditingController();
and in the list tile inside text form field set its controller as c and inside ontap function of list tile do this .
scan().then(()=>setState((){
c.text = barcode;
}));
then function takes a parameter which is automatically suggested to you as you write the code . I have tried only in VSCode and android studio .
So make sure you pass the right parameter to then function or you might get an error .
So, looks like the then() needs a type declared. Passing in String fixed it.
scan().then((String)=>setState((){
c.text = barcode;
}));