Flutter, Sending Form Data to Email - flutter

I would like to create a contact form and would like to know: How to send data from a contact form to my email?
I would like to see a working example.
I wanted to submit a form like this:
return new Scaffold(
appBar: new AppBar(
title: new Text(widget.title),
actions: <Widget>[
new IconButton(icon: const Icon(Icons.save), onPressed: () {})
],
),
body: new Column(
children: <Widget>[
new ListTile(
leading: const Icon(Icons.person),
title: new TextField(
decoration: new InputDecoration(
hintText: "Name",
),
),
),
new ListTile(
leading: const Icon(Icons.phone),
title: new TextField(
decoration: new InputDecoration(
hintText: "Phone",
),
),
),
new ListTile(
leading: const Icon(Icons.email),
title: new TextField(
decoration: new InputDecoration(
hintText: "Email",
),
),
),

You can navigate to default Email app. You can also set the following attributes from your flutter app.
to mail ID,
subject and
body
using url_launcher plugin.
Steps:
Add this to your package's pubspec.yaml file:
url_launcher: "^3.0.1"
main.dart file
import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher.dart';
void main() => runApp(new MaterialApp(home: new MyApp(), debugShowCheckedModeBanner: false,));
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => new _MyAppState();
}
class _MyAppState extends State<MyApp> {
#override
Widget build(BuildContext context) {
return new Scaffold(
body: new Center(
child: new RaisedButton(onPressed: () => _launchURL('xxx#gmail.com', 'Flutter Email Test', 'Hello Flutter'), child: new Text('Send mail'),),
),
);
}
_launchURL(String toMailId, String subject, String body) async {
var url = 'mailto:$toMailId?subject=$subject&body=$body';
if (await canLaunch(url)) {
await launch(url);
} else {
throw 'Could not launch $url';
}
}
}

Try flutter_email_sender package. Here is an example taken from their github.
import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_email_sender/flutter_email_sender.dart';
import 'package:image_picker/image_picker.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String attachment;
final _recipientController = TextEditingController(
text: 'example#example.com',
);
final _subjectController = TextEditingController(text: 'The subject');
final _bodyController = TextEditingController(
text: 'Mail body.',
);
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
Future<void> send() async {
final Email email = Email(
body: _bodyController.text,
subject: _subjectController.text,
recipients: [_recipientController.text],
attachmentPath: attachment,
);
String platformResponse;
try {
await FlutterEmailSender.send(email);
platformResponse = 'success';
} catch (error) {
platformResponse = error.toString();
}
if (!mounted) return;
_scaffoldKey.currentState.showSnackBar(SnackBar(
content: Text(platformResponse),
));
}
#override
Widget build(BuildContext context) {
final Widget imagePath = Text(attachment ?? '');
return MaterialApp(
theme: ThemeData(primaryColor: Colors.red),
home: Scaffold(
key: _scaffoldKey,
appBar: AppBar(
title: Text('Plugin example app'),
actions: <Widget>[
IconButton(
onPressed: send,
icon: Icon(Icons.send),
)
],
),
body: SingleChildScrollView(
child: Center(
child: Padding(
padding: EdgeInsets.all(8.0),
child: Column(
mainAxisSize: MainAxisSize.max,
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Padding(
padding: EdgeInsets.all(8.0),
child: TextField(
controller: _recipientController,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Recipient',
),
),
),
Padding(
padding: EdgeInsets.all(8.0),
child: TextField(
controller: _subjectController,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Subject',
),
),
),
Padding(
padding: EdgeInsets.all(8.0),
child: TextField(
controller: _bodyController,
maxLines: 10,
decoration: InputDecoration(
labelText: 'Body', border: OutlineInputBorder()),
),
),
imagePath,
],
),
),
),
),
floatingActionButton: FloatingActionButton.extended(
icon: Icon(Icons.camera),
label: Text('Add Image'),
onPressed: _openImagePicker,
),
),
);
}
void _openImagePicker() async {
File pick = await ImagePicker.pickImage(source: ImageSource.gallery);
setState(() {
attachment = pick.path;
});
}
}

Please check "mailer" package from flutter. It will use smtp to send email from background without opening userinterface app. It has gmail, yahoo mail, mailgun options to send email.
Reference link :
https://pub.dartlang.org/packages/mailer

If you wanna send it silence and without pop-up any email dialog, you may consider the way which using firebase extension and an SMTP provider.
For my example, I'm using Firebase as our backend API, so we choose an extension of Firebase called "trigger email" to send emails silently.
After you set up an SMTP provider and decided to choose the "Firebase trigger email extension", you can send emails through the form you made in Flutter code silently.
I hope it helps.

Related

Flutter gives error message "Missing concrete implementation of 'State.build" in spite of declaring the override

Error message :
Missing concrete implementation of 'State.build'.
Try implementing the missing method, or make the class abstract.
I get the above error for class _ResetPasswordViewState which is located on Line 13 , in the code below. I get the error message in spite of writing the code for that override. I started getting the error on writing the code for Future passwordReset(), which starts on Line 22. Can someone tell me the mistake I did .
This is the code of my Password Reset file.
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:secure_pass/services/auth/auth_exceptions.dart';
import 'package:secure_pass/utilities/dialogs/error_dialog.dart';
class ResetPasswordView extends StatefulWidget {
const ResetPasswordView({Key? key}) : super(key: key);
#override
State<ResetPasswordView> createState() => _ResetPasswordViewState();
}
class _ResetPasswordViewState extends State<ResetPasswordView> {
final _email = TextEditingController();
#override
void dispose() {
_email.dispose();
super.dispose();
}
Future passwordReset() async{
try {
await FirebaseAuth.instance.sendPasswordResetEmail(email: _email.text);
showDialog(
context: context,
builder: (context) {
return const AlertDialog(
content : Text('Password reset link sent! Check your email'),
);
}
);
} on UserNotFoundAuthException {
await showErrorDialog(
context,
'User not found',
);
} on InvalidEmailAuthException {
await showErrorDialog(
context,
'This is an invalid email address',
);
} on GenericAuthException {
await showErrorDialog(
context,
'Please try again',
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.deepPurple[200],
elevation: 0,
),
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Padding(
padding: EdgeInsets.symmetric(horizontal: 23.0),
child: Text(
"Enter your Email and we will send you a password reset link",
textAlign: TextAlign.center,
),
),
const SizedBox(height: 10),
//email textfield
Padding(
padding: const EdgeInsets.symmetric(horizontal: 25.0),
child: Container(
decoration: BoxDecoration(
color: Colors.grey[200],
border: Border.all(color: Colors.white),
borderRadius: BorderRadius.circular(12),
),
child: Padding(
padding: const EdgeInsets.only(left: 20.0),
child: TextField(
controller: _email,
enableSuggestions: false,
autocorrect: false,
keyboardType: TextInputType.emailAddress,
decoration: const InputDecoration(
hintText: 'Enter your email here',
border: InputBorder.none
),
),
),
),
),
const SizedBox(height: 10),
MaterialButton(
onPressed: passwordReset,
child: Text('Reset Password'),
color: Colors.deepPurple[200],
),
],
),
);
}
}
}
Because you have put you build Widget method inside another method which is the reset password and the stateful widget is looking for the build method in the first stage to run it . i know you did it by mistake and you forgot a } at the end of the fucntion of the reset password, just add it and you will be good to go !

How to use GetX on a value?

I want to make a Password TextField in which the content visibility can be controlled by the suffix icon.
The code may like this:
import 'package:flutter/material.dart';
import 'package:get/get.dart';
void main() {
runApp(TestGetX());
}
class TestGetX extends StatelessWidget {
var eyeClosed = true.obs;
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text("Test GetX"),
),
body: Align(
alignment: Alignment.center,
child: Padding(
padding: EdgeInsets.all(20),
child: TextFormField(
obscureText: eyeClosed.value,
decoration: InputDecoration(
icon: Icon(
Icons.security,
color: Colors.purple,
),
hintText: "Your Password",
hintStyle: TextStyle(color: Colors.grey),
suffix: Obx(
() => InkWell(
child: eyeClosed.value
? Icon(Icons.visibility_off, color: Colors.grey)
: Icon(Icons.visibility, color: Colors.purple),
onTap: () {
eyeClosed.value = !eyeClosed.value;
},
),
),
),
),
),
),
),
);
}
}
The suffix icon can be controlled by the Obx(), but the obscureText doesn't work. The direct way is to use Obx() on the TextFormField, but I don't think it is the best way.
Here is the result:
You need to wrap Obx() in TextFormField
Obx(() => TextFormField(...))
Create a controller for your login screen
class LoginController extends GetxController {
RxBool hidePassword = true.obs;
final passwordTextController = TextEditingController();
}
Extends your login screen widget from GetWidget
class LoginScreen extends GetWidget<LoginController> {
final LoginController controller = Get.find<LoginController>();
#override
Widget build(BuildContext context) {
return(); //Define your widget
}
}
Wrap your textfield in Obx(()=> )
Obx(() => FormBuilderTextField(
name: 'password',
controller: controller.passwordTextController,
obscureText: controller.hidePassword.value,
decoration: InputDecoration(
suffixIcon: IconButton(
icon: controller.hidePassword.value ? Icon(Icons.visibility_off)
: Icon(Icons.visibility),
onPressed: () {
controller.hidePassword.value = !controller.hidePassword.value;
},
),
),
),
I have tried with your code & works fine with a little bit change
class LoginPage extends GetView<LoginController>
Also wrap the whole textFormField in Obx(()=>)
i extend a controller for taking values & calling methods in Getx.i can share my full code if you need.
You should use StatefulWidget when your state is changing. Plus, you can reach the same result you want, without "Get" package.
I show you an example here:
import 'package:flutter/material.dart';
class Example extends StatefulWidget {
#override
_ExampleState createState() => _ExampleState();
}
class _ExampleState extends State<Example> {
bool hidePassword = true;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 15),
child: TextFormField(
obscureText: hidePassword, // which is true by default
decoration: InputDecoration(
hintText: "Enter Password",
suffixIcon: IconButton(
icon: hidePassword == false
? Icon(
Icons.visibility_rounded,
color: Colors.purple,
)
: Icon(
Icons.visibility_off_rounded,
color: Colors.grey,
),
onPressed: () {
setState(() {
// here we change the value
// if it's false, it gets true
// and if it's true, it gets false
hidePassword = !hidePassword;
});
},
),
),
),
),
),
);
}
}

connect to open wireless by using wifi_configuration Flutter

may i ask how to connect to an open hotspot - wireless- by using wifi_configuration package
cause i just found a method that allow to connect to encrypted wireless networks.
WifiConfiguration.connectToWifi("wirelessname","wirelesspassword","packagename");
inside WifiConfiguration class there is just one method that can be used for connecting.
is there any other library that can connect to an open hotspot or is there a way to do that by using wifi_configuration library ?
Apple mentioned that we need just two parameters to pass which is of course the ssid and the packagename
init(ssid: String)
Creates a new hotspot configuration, identified by an SSID, for an open Wi-Fi network.
i override the method connectToWifi to receive just one parameter but this didn't work.
thanks in advance
You can copy paste run full code below
You can use package https://pub.dev/packages/wifi_utils
You can call Wifi.connection and provide ssid and password
code snippet
import 'package:wifi/wifi.dart';
...
Future<Null> connection() async {
Wifi.connection(ssid, password).then((v) {
print(v);
});
}
working demo
full code
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:wifi/wifi.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Wifi',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
String _wifiName = 'click button to get wifi ssid.';
int level = 0;
String _ip = 'click button to get ip.';
List<WifiResult> ssidList = [];
String ssid = '', password = '';
#override
void initState() {
super.initState();
loadData();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Wifi'),
centerTitle: true,
),
body: SafeArea(
child: ListView.builder(
padding: EdgeInsets.all(8.0),
itemCount: ssidList.length + 1,
itemBuilder: (BuildContext context, int index) {
return itemSSID(index);
},
),
),
);
}
Widget itemSSID(index) {
if (index == 0) {
return Column(
children: [
Row(
children: <Widget>[
RaisedButton(
child: Text('ssid'),
onPressed: _getWifiName,
),
Offstage(
offstage: level == 0,
child: Image.asset(
level == 0 ? 'images/wifi1.png' : 'images/wifi$level.png',
width: 28,
height: 21),
),
Text(_wifiName),
],
),
Row(
children: <Widget>[
RaisedButton(
child: Text('ip'),
onPressed: _getIP,
),
Text(_ip),
],
),
TextField(
decoration: InputDecoration(
border: UnderlineInputBorder(),
filled: true,
icon: Icon(Icons.wifi),
hintText: 'Your wifi ssid',
labelText: 'ssid',
),
keyboardType: TextInputType.text,
onChanged: (value) {
ssid = value;
},
),
TextField(
decoration: InputDecoration(
border: UnderlineInputBorder(),
filled: true,
icon: Icon(Icons.lock_outline),
hintText: 'Your wifi password',
labelText: 'password',
),
keyboardType: TextInputType.text,
onChanged: (value) {
password = value;
},
),
RaisedButton(
child: Text('connection'),
onPressed: connection,
),
],
);
} else {
return Column(children: <Widget>[
ListTile(
leading: Image.asset('images/wifi${ssidList[index - 1].level}.png',
width: 28, height: 21),
title: Text(
ssidList[index - 1].ssid,
style: TextStyle(
color: Colors.black87,
fontSize: 16.0,
),
),
dense: true,
),
Divider(),
]);
}
}
void loadData() async {
Wifi.list('').then((list) {
setState(() {
ssidList = list;
});
});
}
Future<Null> _getWifiName() async {
int l = await Wifi.level;
String wifiName = await Wifi.ssid;
setState(() {
level = l;
_wifiName = wifiName;
});
}
Future<Null> _getIP() async {
String ip = await Wifi.ip;
setState(() {
_ip = ip;
});
}
Future<Null> connection() async {
Wifi.connection(ssid, password).then((v) {
print(v);
});
}
}

Navigator.pop() not refresh data from database

I am trying to make create data with localhost mysql in separate page with home and after that go back to home that contain list of data with Navigator.pop(context). the problem is when i've done add data, the page go back to home and new data not appear in list, but after i refresh debug the data appear. what should i do to get new data in list after create data?
main.dart
import "package:flutter/material.dart";
import "dart:async";
import 'package:http/http.dart' as http;
import 'dart:convert';
import "Detail.dart";
import "CreatePegawai.dart";
void main() {
runApp(new MaterialApp(
title: "CRUD PEGAWAI",
home: new Home(),
));
}
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
Future<List> readData() async {
final response = await http.get("http://10.0.2.2/modelpegawai/read.php");
return json.decode(response.body);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: new AppBar(
title: new Text("List Data Pegawai"),
leading: new Icon(Icons.home),
backgroundColor: Colors.blue[300],
),
floatingActionButton: new FloatingActionButton(
child: new Icon(Icons.add),
onPressed: ()=>Navigator.of(context).push(
new MaterialPageRoute(
builder: (BuildContext context)=> new CreatePegawai(),
)
),
),
body: new FutureBuilder<List>(
future: readData(),
builder: (context, snapshot) {
if (snapshot.hasError) {
print(snapshot.error);
}
return snapshot.hasData
? new ItemList(list: snapshot.data)
: new Center(
child: new CircularProgressIndicator(),
);
},
),
backgroundColor: Colors.yellow[200],
);
}
}
class ItemList extends StatelessWidget {
final List list;
ItemList({this.list});
#override
Widget build(BuildContext context) {
return new ListView.builder(
itemCount: list == null ? 0 : list.length,
itemBuilder: (context, i) {
return new Container(
padding: const EdgeInsets.all(10.0),
child: new GestureDetector(
onTap: ()=>Navigator.of(context).push(
new MaterialPageRoute(
builder: (BuildContext context)=>new Detail(list:list, index:i)
)
),
child: new Card(
child: new ListTile(
title: new Text(
list[i]['nama'],
style: new TextStyle(fontSize: 20.0),
),
leading: new Icon(Icons.assignment_ind),
subtitle: new Text(
"Asal : ${list[i]['asalKota']}",
style: new TextStyle(fontSize: 16.0),
),
)),
));
});
}
}
createPegawai.dart
import "package:flutter/material.dart";
import 'package:http/http.dart' as http;
import 'package:intl/intl.dart';
import 'package:datetime_picker_formfield/datetime_picker_formfield.dart';
class CreatePegawai extends StatefulWidget {
#override
_CreatePegawaiState createState() => _CreatePegawaiState();
}
class _CreatePegawaiState extends State<CreatePegawai> {
DateTime date2;
TextEditingController controllerNIP = new TextEditingController();
TextEditingController controllerNama = new TextEditingController();
TextEditingController controllerTgl = new TextEditingController();
TextEditingController controllerAsalKota = new TextEditingController();
TextEditingController controllerDept = new TextEditingController();
TextEditingController controllerEmail = new TextEditingController();
TextEditingController controllerPass = new TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: new AppBar(
title: new Text("Tambah Pegawai"),
),
body: Padding(
padding: const EdgeInsets.all(20.0),
child: ListView(
children: <Widget>[
new Column(
children: <Widget>[
new Text(
"Form Tambah Pegawai",
style: new TextStyle(
fontSize: 20.0,
),
),
nip(),
nama(),
tgl(),
asalKota(),
kodeDept(),
email(),
pass(),
new Padding(
padding: const EdgeInsets.all(10.0),
),
tombol(),
],
),
],
),
));
}
Widget nip() {
return TextField(
controller: controllerNIP,
decoration: new InputDecoration(
hintText: "NIP 3 Angka",
labelText: "NIP",
),
);
}
Widget nama() {
return TextField(
controller: controllerNama,
decoration: new InputDecoration(
hintText: "Masukan Nama",
labelText: "Nama",
),
);
}
Widget tgl() {
return new Container(
child: DateTimePickerFormField(
controller: controllerTgl,
inputType: InputType.date,
format: DateFormat("dd-MM-yyyy"),
initialDate: DateTime(2019, 1, 1),
editable: false,
decoration:
InputDecoration(labelText: 'Date', hasFloatingPlaceholder: false),
onChanged: (dt) {
setState(() => date2 = dt);
},
),
);
}
Widget asalKota() {
return TextField(
controller: controllerAsalKota,
decoration: new InputDecoration(
hintText: "Masukan Kota Asal",
labelText: "Kota Asal",
),
);
}
Widget kodeDept() {
return TextField(
controller: controllerDept,
decoration: new InputDecoration(
hintText: "Dept",
labelText: "Departmen",
),
);
}
Widget email() {
return TextFormField(
controller: controllerEmail,
keyboardType: TextInputType.emailAddress, //KEYBOARD TYPENYA ADALAH EMAIL ADDRESS AGAR SYMBOL # DILETAKKAN DIDEPAN KETIKA KEYBOARD DI TAMPILKAN
decoration: InputDecoration(
labelText: "Email",
hintText: "email#provide.com",
),
);
}
Widget pass() {
return TextFormField(
controller: controllerPass,
obscureText: true, //membuat titik2 pada inputan/tidak keliatan text
decoration: InputDecoration(
labelText: "Password",
hintText: "Masukan password",
),
);
}
Widget tombol() {
return RaisedButton(
child: new Text("Tambah"),
color: Colors.blueAccent,
onPressed: () {
create();
Navigator.pop(context);
},
);
}
void create(){
var url = "http://10.0.2.2/modelpegawai/create.php";
var formatter = new DateFormat('yyyy-MM-dd');
String formatted = formatter.format(date2);
http.post(url, body:{
"nip": controllerNIP.text,
"nama": controllerNama.text,
"tgl": formatted,
"asalKota": controllerAsalKota.text,
"dept": controllerDept.text,
"email": controllerEmail.text,
"pass": controllerPass.text,
});
}
}
A simple trick to achieve your requirement is pass some data when poping from second screen.
// This is where you push to second screen from first screen
// Make sure you a method to get data from server
// And call that function when popped
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => SecondScreen())).then(
(data){
if(data!=null && data){
getDataFromServer();
});
// This is where you are poping from second screen.
// Pass a bool whether you want refresh first screen or not.
Navigator.of(context).pop(true)
I Finally can solve this problem. the new data can show with add async and await in the createData() function like this
void create() async {
var url = "http://10.0.2.2/modelpegawai/create.php";
var formatter = new DateFormat('yyyy-MM-dd');
String formatted = formatter.format(date2);
await http.post(url, body:{
"nip": controllerNIP.text,
"nama": controllerNama.text,
"tgl": formatted,
"asalKota": controllerAsalKota.text,
"dept": controllerDept.text,
"email": controllerEmail.text,
"pass": controllerPass.text,
});
}

TextFormField Validator not showing validator message

I tried to create this form with validation, so it shows the errors when the user returns each field. But for some reason it doesn't work. I have no reason why. I'm just stuck now.
Here's the code:
import 'package:flutter/material.dart';
import 'package:validate/validate.dart';
void main() => runApp(new MaterialApp(
title: 'Forms in Flutter',
home: new LoginForm(),
theme: ThemeData.dark(),
));
class LoginForm extends StatefulWidget {
String email;
String password;
final Function saveEmail;
final Function savePassword;
final Function attemptLogin;
LoginForm({this.email, this.password, this.saveEmail, this.savePassword,
this.attemptLogin});
#override
LoginFormState createState(){
return new LoginFormState();
}
}
class LoginFormState extends State<LoginForm> {
final loginFormKey = GlobalKey<FormState>();
final emailController = new TextEditingController();
final passController = new TextEditingController();
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('Login'),
),
body: new Container(
padding: new EdgeInsets.all(10.0),
child: new Form(
key: loginFormKey,
child: new Column(
children: <Widget>[
new Row(
children: <Widget>[
new Container(
width: 2.0,
height: 18.0,
color: Colors.white,
),
new Container(
width: 5.0,
height: 0.0
),
new Expanded(child: new TextFormField(
decoration: new InputDecoration.collapsed(
hintText: "EMAIL",
),
validator: (String value) {
if (!Validate.isEmail(value)) {
return 'Please enter Email';
}
},
onFieldSubmitted: (val) {
print(loginFormKey.currentState.validate());
if (loginFormKey.currentState.validate()) {
widget.email = val;
widget.saveEmail(val);
}
},
controller: emailController,
),)
],
),
new Row(
children: <Widget>[
new Container(
width: 2.0,
height: 18.0,
color: Colors.white,
padding: const EdgeInsets.fromLTRB(0.0, 0.0, 5.0, 0.0),
),
new Container(
width: 5.0,
height: 0.0
),
new Expanded(child: new TextFormField(
obscureText: true,
decoration: new InputDecoration.collapsed(
hintText: 'PASSWORD',
),
validator: (val) =>
val.length < 6 ?
'Still too short' : '',
onFieldSubmitted: (val) {
if (loginFormKey.currentState.validate()) {
widget.email = emailController.text;
print(widget.email);
widget.saveEmail(emailController.text);
widget.password = val;
print(widget.password);
widget.savePassword(val);
widget.attemptLogin();
}
},
controller: passController,
),)
],
)
],
),
),
)
);
}
}
I really don't know what's causing this. It seems like everything in the onfieldSubmitted part of the fields don't work. If I remove the If statements, they work okay, but once it's added it gives no response.
Seems like something simple but I'm just missing the point. Any help would be greatly appreciated. Thanks.
am having the same issue now. I think the !Validate.isEmail(value) is not working.
I commented it out and my code ran well. Try writing your own custom email validation instead of using !Validate.isEmail(value)
The onFieldSubmitted property works when clicking enter or submit on the keyboard. I think, you should add a submit button for submitting because your validations works for form, not an field or input. So, It means if a user entered the email address but this user didn't enter any password, it will take validation error message for password on email field when clicked the enter button. It's not a good feedback. If you use a submit button, it should shows more good feedback for validation messages.
// The button widget
new FlatButton(
onPressed: () => this._submit(),
child: new Text('Login')
);
// The submit function
void _submit() {
if (this.loginFormKey.currentState.validate()) {
this.loginFormKey.currentState.save();
// Do your jobs with the validated form data.
}
}