How can I send an Email through Website Contact Form - google-cloud-functions

I am implementing a contact form on a website with Flutter web.
To make this form functional, I need to send it as an email to a recipient.
I am not even aware of what I should search for to implement this. What are the different implementation options for this case?
If I use Firebase for hosting, I could probably use a callable cloud function. Would this make any sense?
This is a pretty generic form that I implemented:
class ContactMe extends StatefulWidget {
const ContactMe({Key key}) : super(key: key);
#override
_ContactMeState createState() => _ContactMeState();
}
class _ContactMeState extends State<ContactMe> {
final _formKey = GlobalKey<FormState>();
String _name;
String _email;
String _message;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
padding: const EdgeInsets.all(15),
margin: const EdgeInsets.only(top: 15),
child: Column(
children: [
Align(
alignment: Alignment.centerLeft,
child: const _BrandName(),
),
Container(
padding: const EdgeInsets.all(55),
child: Form(
key: _formKey,
child: Column(
children: [
TextFormField(
decoration: InputDecoration(
helperText: 'Please enter name',
hintText: 'Darth Vader'),
cursorColor: kDarkBlue,
onChanged: (value) {
_name = value;
_formKey.currentState.validate();
},
validator: (value) {
if (value.isEmpty) {
return 'Please enter valid name';
}
return null;
},
),
TextFormField(
decoration: InputDecoration(
helperText: 'Please enter email',
hintText: 'darth.vader#star.com'),
cursorColor: kDarkBlue,
onChanged: (value) {
_email = value;
_formKey.currentState.validate();
},
validator: (value) {
if (value.isEmpty) {
return 'Please enter valid email';
}
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 email';
}
return null;
},
),
TextFormField(
decoration: InputDecoration(
helperText: 'Please enter subject',
hintText: 'Optimizing Lightsaber Production'),
cursorColor: kDarkBlue,
onChanged: (value) {
_name = value;
_formKey.currentState.validate();
},
validator: (value) {
if (value.isEmpty) {
return 'Please enter a valid subject';
}
return null;
},
),
TextFormField(
maxLines: 14,
cursorColor: kDarkBlue,
decoration: InputDecoration(
helperText: 'Please enter message',
),
onChanged: (value) {
_message = value;
_formKey.currentState.validate();
},
validator: (value) {
if (value.isEmpty) {
return 'Please enter a message';
}
return null;
},
)
],
),
),
),
ElevatedButton(
style: ElevatedButton.styleFrom(primary: kBrightGreen),
onPressed: () {
if (_formKey.currentState.validate()) {
//todo: add here functionalitty
//todo: Show a Succesful send message, then transfer to primary
Navigator.pushNamed(context, kScreenPrimary);
}
},
child: Text(
'Submit',
style: kTitleStyle,
),
)
],
),
),
);
}
}
P.S. I am using Flutter: 1.23.0-18.1.pre master channel.

Related

REST Api Login With POST Method

I wanted to do the classic login with a JSON but it does not work, in the sense that even if you put the wrong credentials from 200 (ie ok). I only put a JSON file (login.json), at this point I doubt that we need to create a particular environment to manage the JSON .. the server where the JSON resides is a HOSTING on the L.A.M.P. (Linux / Apache / MySQL / PHP)
login_page.dart
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_http_post_request/api/api_service.dart';
import 'package:flutter_http_post_request/model/login_model.dart';
import '../ProgressHUD.dart';
class LoginPage extends StatefulWidget {
#override
_LoginPageState createState() => _LoginPageState();
}
class _LoginPageState extends State<LoginPage> {
bool hidePassword = true;
bool isApiCallProcess = false;
GlobalKey<FormState> globalFormKey = GlobalKey<FormState>();
LoginRequestModel loginRequestModel;
final scaffoldKey = GlobalKey<ScaffoldState>();
#override
void initState() {
super.initState();
loginRequestModel = new LoginRequestModel();
}
#override
Widget build(BuildContext context) {
return ProgressHUD(
child: _uiSetup(context),
inAsyncCall: isApiCallProcess,
opacity: 0.3,
);
}
Widget _uiSetup(BuildContext context) {
return Scaffold(
key: scaffoldKey,
backgroundColor: Theme.of(context).accentColor,
body: SingleChildScrollView(
child: Column(
children: <Widget>[
Stack(
children: <Widget>[
Container(
width: double.infinity,
padding: EdgeInsets.symmetric(vertical: 30, horizontal: 20),
margin: EdgeInsets.symmetric(vertical: 85, horizontal: 20),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: Theme.of(context).primaryColor,
boxShadow: [
BoxShadow(
color: Theme.of(context).hintColor.withOpacity(0.2),
offset: Offset(0, 10),
blurRadius: 20)
],
),
child: Form(
key: globalFormKey,
child: Column(
children: <Widget>[
SizedBox(height: 25),
Text(
"Login",
style: Theme.of(context).textTheme.headline2,
),
SizedBox(height: 20),
new TextFormField(
keyboardType: TextInputType.emailAddress,
onSaved: (input) => loginRequestModel.email = input,
validator: (input) => !input.contains('#')
? "Email Id should be valid"
: null,
decoration: new InputDecoration(
hintText: "Email Address",
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(
color: Theme.of(context)
.accentColor
.withOpacity(0.2))),
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(
color: Theme.of(context).accentColor)),
prefixIcon: Icon(
Icons.email,
color: Theme.of(context).accentColor,
),
),
),
SizedBox(height: 20),
new TextFormField(
style:
TextStyle(color: Theme.of(context).accentColor),
keyboardType: TextInputType.text,
onSaved: (input) =>
loginRequestModel.password = input,
validator: (input) => input.length < 3
? "Password should be more than 3 characters"
: null,
obscureText: hidePassword,
decoration: new InputDecoration(
hintText: "Password",
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(
color: Theme.of(context)
.accentColor
.withOpacity(0.2))),
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(
color: Theme.of(context).accentColor)),
prefixIcon: Icon(
Icons.lock,
color: Theme.of(context).accentColor,
),
suffixIcon: IconButton(
onPressed: () {
setState(() {
hidePassword = !hidePassword;
});
},
color: Theme.of(context)
.accentColor
.withOpacity(0.4),
icon: Icon(hidePassword
? Icons.visibility_off
: Icons.visibility),
),
),
),
SizedBox(height: 30),
FlatButton(
padding: EdgeInsets.symmetric(
vertical: 12, horizontal: 80),
onPressed: () {
if (validateAndSave()) {
print(loginRequestModel.toJson());
setState(() {
isApiCallProcess = true;
});
APIService apiService = new APIService();
apiService.login(loginRequestModel).then((value) {
if (value != null) {
setState(() {
isApiCallProcess = false;
});
if (value.token.isNotEmpty) {
final snackBar = SnackBar(
content: Text("Login Successful"));
scaffoldKey.currentState
.showSnackBar(snackBar);
} else {
final snackBar =
SnackBar(content: Text(value.error));
scaffoldKey.currentState
.showSnackBar(snackBar);
}
}
});
}
},
child: Text(
"Login",
style: TextStyle(color: Colors.white),
),
color: Theme.of(context).accentColor,
shape: StadiumBorder(),
),
SizedBox(height: 15),
],
),
),
),
],
),
],
),
),
);
}
bool validateAndSave() {
final form = globalFormKey.currentState;
if (form.validate()) {
form.save();
return true;
}
return false;
}
}
api_service.dart
import 'package:http/http.dart' as http;
import 'dart:convert';
import '../model/login_model.dart';
class APIService {
Future<LoginResponseModel> login(LoginRequestModel requestModel) async {
//String url = "https://reqres.in/api/login";
String url = "https://www.nextesa.it/api/login";
final response = await http.post(url, body: requestModel.toJson());
if (response.statusCode == 200 || response.statusCode == 400) {
return LoginResponseModel.fromJson(
json.decode(response.body),
);
} else {
throw Exception('Failed to load data!');
}
}
}
login_mode.dart
class LoginResponseModel {
final String token;
final String error;
LoginResponseModel({this.token, this.error});
factory LoginResponseModel.fromJson(Map<String, dynamic> json) {
return LoginResponseModel(
token: json["token"] != null ? json["token"] : "",
error: json["error"] != null ? json["error"] : "",
);
}
}
class LoginRequestModel {
String email;
String password;
LoginRequestModel({
this.email,
this.password,
});
Map<String, dynamic> toJson() {
Map<String, dynamic> map = {
'email': email.trim(),
'password': password.trim(),
};
return map;
}
}
File json
{
"email": "eve.holt#reqres.in",
"password": "cityslicka"
}

Flutter: How do i generate a json file from List using GetX package

How do i generate JSON from multiple lists using GetX package? I am using GetX package for Flutter to pass data between screens in Flutter. The list is obtained from Episode5.dart file. The list is vieewed in MyApp file which is also the place where JSON Generate Button is kept. On clicking the button, i want the json created using the data in the list above. I have the following code:
1. Episode5.dart
class Episode5 extends StatefulWidget {
#override
_Episode5State createState() => _Episode5State();
}
class _Episode5State extends State<Episode5> {
TextEditingController nameController = TextEditingController();
TextEditingController emailController = TextEditingController();
final form = GlobalKey<FormState>();
static var _focusNode = new FocusNode();
bool update = false;
int currentIndex = 0;
List<User> userList = [
User(name: "a", email: "a"),
User(name: "d", email: "b"),
User(name: "c", email: "c"),
];
#override
Widget build(BuildContext context) {
Widget bodyData() => DataTable(
onSelectAll: (b) {},
sortColumnIndex: 0,
sortAscending: true,
columns: <DataColumn>[
DataColumn(label: Text("Name"), tooltip: "To Display name"),
DataColumn(label: Text("Email"), tooltip: "To Display Email"),
DataColumn(label: Text("Update"), tooltip: "Update data"),
],
rows: userList
.map(
(user) => DataRow(
cells: [
DataCell(
Text(user.name),
),
DataCell(
Text(user.email),
),
DataCell(
IconButton(
onPressed: () {
currentIndex = userList.indexOf(user);
_updateTextControllers(user); // new function here
},
icon: Icon(
Icons.edit,
color: Colors.black,
),
),
),
],
),
)
.toList(),
);
return Scaffold(
appBar: AppBar(
title: Text("Data add to List Table using Form"),
),
body: Container(
child: Column(
children: <Widget>[
bodyData(),
Padding(
padding: EdgeInsets.all(10.0),
child: Form(
key: form,
child: Container(
child: Column(
children: <Widget>[
TextFormField(
controller: nameController,
focusNode: _focusNode,
keyboardType: TextInputType.text,
autocorrect: false,
maxLines: 1,
validator: (value) {
if (value.isEmpty) {
return 'This field is required';
}
return null;
},
decoration: new InputDecoration(
labelText: 'Name',
hintText: 'Name',
labelStyle: new TextStyle(
decorationStyle: TextDecorationStyle.solid),
),
),
SizedBox(
height: 10,
),
TextFormField(
controller: emailController,
keyboardType: TextInputType.text,
autocorrect: false,
maxLines: 1,
validator: (value) {
if (value.isEmpty) {
return 'This field is required';
}
return null;
},
decoration: new InputDecoration(
labelText: 'Email',
hintText: 'Email',
labelStyle: new TextStyle(
decorationStyle: TextDecorationStyle.solid)),
),
SizedBox(
height: 10,
),
Column(
children: <Widget>[
Center(
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
TextButton(
child: Text("Add"),
onPressed: () {
form.currentState.save();
addUserToList(
nameController.text,
emailController.text,
);
},
),
TextButton(
child: Text("Update"),
onPressed: () {
form.currentState.save();
updateForm();
},
),
],
),
Row(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
ElevatedButton(
child: Text("Save and Exit"),
onPressed: () {
form.currentState.save();
addUserToList(
nameController.text,
emailController.text,
);
Navigator.pop(context, userList);
},
),
],
),
],
),
),
],
),
],
),
),
),
),
],
),
),
);
}
void updateForm() {
setState(() {
User user = User(name: nameController.text, email: emailController.text);
userList[currentIndex] = user;
});
}
void _updateTextControllers(User user) {
setState(() {
nameController.text = user.name;
emailController.text = user.email;
});
}
void addUserToList(name, email) {
setState(() {
userList.add(User(name: name, email: email));
});
}
}
1. Main.dart
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
return Scaffold(
appBar: AppBar(
title: Text("Testing List View Data From second page to first page"),
),
body: Column(
children: <Widget>[
Expanded(
child: GetBuilder<FormController>(
builder: (controller) => ListView.builder(
itemCount: controller.userList.length,
itemBuilder: (context, index) => Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Text(controller.userList[index].name),
Text(controller.userList[index].email),
],
),
),
),
),
SizedBox(
height: 10.0,
),
ElevatedButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Episode5(),
),
);
},
child: Text("Go to Form"),
),
SizedBox(
height: 10.0,
),
ElevatedButton(
onPressed: () {
generateJSON();
},
child: Text("Generate JSON"),
),
],
),
);
}
generateJSON() {
GenerateJSON generate =
GenerateJSON(controller.userList, controller.schooList);
String jsonAddress = jsonEncode(generate);
print(jsonAddress);
}
}
2. Model.dart
class User {
String name;
String email;
User({this.name, this.email});
Map toJson() => {
'name': name,
'age': email,
};
}
class GenerateJSON {
List<User> user;
List<School> school;
GenerateJSON([this.user, this.school]);
Map toJson() {
List<Map> user =
this.user != null ? this.user.map((e) => e.toJson()).toList() : null;
return {'User': user, 'School': school};
}
}
It's exist now a powerful and flexible package on pub.dev named json_bridge.
For those who want to deal with json file, checkout it here: https://pub.dev/packages/json_bridge

How to update data in mysql by flutter

I try to edit data in mysql from flutter. I send Id from page one to page two And by id I Inquire about specific data then edit it With the condition where Id=Id. Now when the application works, I can make sure Id send to php file. I try here to update field of name.
Logcat
I/flutter: tappedddd http://xxxxxxxxx/ccv.php?id=66
I can see ID is sent with the link but data now do not change in the database.I don't know what is problem. Anyone know solution for this problem?
my full code:
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:http/http.dart' as http;
import 'dart:async';
import 'dart:convert';
import 'MyPreferences.dart';
class Update extends StatefulWidget {
var getid;
Update({Key key, this.getid}) : super(key: key);
#override
_UpdateState createState() => new _UpdateState();
}
class _UpdateState extends State<Update> {
MyPreferences _myPreferences = MyPreferences();
var getid;
var _isLoading = false;
var data;
var _username = "";
var _phone = "";
var _password = "";
var image ="";
var _phoneController = new TextEditingController();
var _firstnameController = new TextEditingController();
var _lastnameController = new TextEditingController();
Future<String> _ShowDialog(String msg) async {
return showDialog<String>(
context: context,
barrierDismissible: false, // user must tap button!
builder: (BuildContext context) {
return new AlertDialog(
title: new Text('Rewind and remember'),
content: new SingleChildScrollView(
child: new ListBody(
children: <Widget>[
new Text(msg),
],
),
),
actions: <Widget>[
new FlatButton(
child: new Text('Close'),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
);
}
void _editData() async {
var url = "http://xxxxxxxx/ccv.php?id=${widget.getid}";
print("tappedddd $url");
var response = await http.post(url, body: {
"id": widget.getid,
// "id": _userController.text,
"name": _firstnameController.text,
// "name": _phoneController.text,
// "name": _lastnameController.text,
});
if (response.statusCode == 200) {
_ShowDialog("Updated Successfully");
} else {
_ShowDialog("Updated Failer");
}
//onEditedAccount();
//print(_adresseController.text);
}
_fetchData() async {
final url =
"http://xxxxxxxxxx/nhy.php?id=${widget.getid}";
final response = await http.get(url);
if (response.statusCode == 200) {
final map = json.decode(response.body);
final videosMap = map["result"];
setState(() {
_isLoading = true;
this.data = videosMap;
_username = data[0]['name'];
image = data[0]['image'];
print(data);
});
}
}
#override
void initState() {
super.initState();
_fetchData();
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: AppBar(
title: Text("Update Profile"),
),
body: new Center(
child: data == null
? new CircularProgressIndicator()
: new ListView(
children: <Widget>[
new Padding(
padding: const EdgeInsets.fromLTRB(5, 100, 5, 5),
child: Column(
children: <Widget>[
new Padding(
padding:
const EdgeInsets.only(top: 20.0, bottom: 25.0),
child: Expanded(flex: 1,
child: Container(
child: Card(
child: new Padding(
padding: const EdgeInsets.all(5.0),
child: Image.network(
image,
width: 300,
height: 300,
fit: BoxFit.cover,
),
),
),
),
),
),
Card (
child: Column(
children: <Widget>[
SizedBox(
height: 10.0,
),
Container(
margin: EdgeInsets.all(4),
child: TextField(
maxLength: 10,
decoration: InputDecoration(
labelText: ("name : "),
filled: true,
hintText: _username),
controller: _firstnameController,
),
),
SizedBox(
height: 5.0,
),
Container(
margin: EdgeInsets.all(4),
child: TextField(
maxLength: 8,
decoration: InputDecoration(
labelText: ("phone : "),
filled: true,
hintText: _phone),
controller: _phoneController,
),
),
SizedBox(
height: 5.0,
),
Container(
margin: EdgeInsets.all(4),
child: TextField(
maxLength: 8,
decoration: InputDecoration(
labelText: ("password : "),
filled: true,
hintText: _password),
controller: _lastnameController,
),
),
SizedBox(
height: 5.0,
),
]
)
),
SizedBox(
width: double.infinity,
child: new FlatButton(
child: const Text('Update'),color: Colors.amber,
padding: EdgeInsets.fromLTRB(100, 18, 100, 18),
onPressed: () { _editData();
},
),
),
SizedBox(
height: 10.0,
),
],
),
)
],
),
));
}
}
php file:
<?php
require_once 'connt.php';
$id=$_POST['id'];
$name =$_POST['name'];
$query="UPDATE topics SET name='$name' WHERE id='$id'";
$exeQuery = mysqli_query($con, $query) ;
if($exeQuery){
echo (json_encode(array('code' =>1, 'message' => 'Modifier avec succee')));
}else {echo(json_encode(array('code' =>2, 'message' => 'Modification Non Terminer')));
}
?>

form.currentstate.validate() failing - Flutter

I need some help with this. My task is to pick the location along with the address and submit it. But for some reasons, the _addPointKey.currentState.validate() is always giving false.
I have a TextFormField for taking the address, a location preview container, a button to open the google_map_location_picker and finally a button to submit the data. All these fields are declared inside a form with _addPointKey key.
Form validation does work, i.e. if the fields are empty, it does show in red that the fields can't be empty. But still, I have some problem with submitting the whole formData. The textFormField becomes null.
I have used google_map_location_picker package for picking the location. Can somebody help?
Thanks in advance.
final GlobalKey<FormState> _addPointKey = GlobalKey<FormState>();
Map<String, dynamic> formData = {
"address": null,
};
Widget _addressField() {
return Container(
margin: EdgeInsets.symmetric(vertical: 10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
"Address of the Collection Center",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 15,
color: Theme.of(context).primaryColor),
),
SizedBox(
height: 10,
),
TextFormField(
decoration: InputDecoration(
border: InputBorder.none,
fillColor: Color(0xfff3f3f4),
filled: true),
maxLines: 4,
validator: (String value) {
if (value.isEmpty) {
return "Address is required";
}
return '';
},
onChanged: (String value) {
formData["address"] = value;
},
onSaved: (String value) {
formData["address"] = value;
},
),
],
),
);
}
Widget _locationPreview() {
return (_pickedLocation != null)
? Container(
height: 300,
decoration: BoxDecoration(
border: Border.all(
width: 2,
color: Theme.of(context).accentColor,
)),
child: GoogleMap(
initialCameraPosition: CameraPosition(
target: _pickedLocation.latLng,
zoom: 14.4746,
),
markers: Set.from(newMarkers),
),
)
: Container(
child: Text(
"Location is required.",
style: TextStyle(
color: Colors.red,
),
),
);
}
Widget _locationButton() {
return RaisedButton(
color: Theme.of(context).accentColor,
onPressed: () async {
LocationResult result = await showLocationPicker(
context,
< API key>,
initialCenter: LatLng(31.1975844, 29.9598339),
myLocationButtonEnabled: true,
layersButtonEnabled: true,
);
setState(() {
_pickedLocation = result;
_addPointKey.currentState.save();
newMarkers.add(Marker(
markerId: MarkerId("newId"),
draggable: false,
position: _pickedLocation.latLng,
onTap: null,
));
});
},
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(
Icons.location_on,
color: Colors.white,
),
Text(
(_pickedLocation == null) ? 'Locate on Map' : 'Change Location',
style: TextStyle(color: Colors.white),
),
],
),
);
}
Widget _addLocationButton() {
return ScopedModelDescendant<MainModel>(
builder: (BuildContext context, Widget widget, MainModel model) {
return model.managingCenter
? CircularProgressIndicator()
: InkWell(
onTap: () async {
print(_addPointKey.currentState.validate());
if (!_addPointKey.currentState.validate() ||
_pickedLocation == null) {
print(formData);
return;
}
_addPointKey.currentState.save();
Map<String, dynamic> successInfo =
await model.addCenter(model.token, formData);
if (successInfo["success"]) {
Navigator.pop(context);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => FutureBuilder(
future: model.fetchCenter(model.token),
builder: (context, authResultSnapShot) {
return authResultSnapShot.connectionState ==
ConnectionState.waiting
? SplashScreen()
: CollectionPoints(model);
})));
} else {
print("Something went wrong");
}
},
child: Container(
height: 50,
alignment: Alignment.center,
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(5)),
boxShadow: <BoxShadow>[
BoxShadow(
color: Colors.grey.shade200,
offset: Offset(2, 4),
blurRadius: 5,
spreadRadius: 2)
],
gradient: LinearGradient(
begin: Alignment.centerLeft,
end: Alignment.centerRight,
colors: [Color(0xfffbb448), Color(0xfff7892b)]),
),
padding: const EdgeInsets.all(10.0),
child: Text('Add the Location',
style: TextStyle(fontSize: 20, color: Colors.white)),
),
);
});
}
void _addPoint() {
showBottomSheet(
context: context,
builder: (context) {
return Container(
padding: EdgeInsets.all(10),
child: Form(
key: _addPointKey,
child: SingleChildScrollView(
child: Column(
children: <Widget>[
_addressField(),
_locationPreview(),
_locationButton(),
_addLocationButton()
],
),
),
),
);
});
}
In the TextFormField validator function you must return null, it indicates the field has correct value and there are no errors. Returning anything other than null will indicate that the field has an invalid value, i've shared the corrected code of the validator function.
TextFormField(
decoration: InputDecoration(
border: InputBorder.none,
fillColor: Color(0xfff3f3f4),
filled: true),
maxLines: 4,
validator: (String value) {
if (value.isEmpty) {
return "Address is required";
}
// return ''; this is causing you the error you must return null
return null; // this is correct
},
onChanged: (String value) {
formData["address"] = value;
},
onSaved: (String value) {
formData["address"] = value;
},
),
A simpler way to create a confirm password on your flutter.
'showSnackBar' bottom pop-up to alert users for errors.
[1]: https://i.stack.imgur.com/zjXLd.png
var _password = '';
var _confirmPassword = '';
// this will called 'onTap'
void signUpUser() async {
if (_password != _confirmPassword){ // you can add your statements here
showSnackBar(context,
"Password does not match. Please re-type again.");
} else {
FirebaseAuthMethods(FirebaseAuth.instance).signUpWithEmail(
email: emailController.text,
password: passwordController.text,
context: context,
);
}
}
// Insert inside your build()
// to you password field.
child: TextFormField(
controller: passwordController,
obscureText: true,
onChanged: (value) {
_password = value;
},
// to your confirm password field.
child: TextFormField(
controller: confirmPasswordController,
obscureText: true,
onChanged: (value) {
_confirmPassword = value;
},
// add this to your Sign-up button
onTap: signUpUser,

How to generate a list of cards based on the number of items in json file

I use the following code to generate 10 predefined cards on a flutter screen which doesn't change:
List cards = new List.generate(10, (i)=>new QuestionCard()).toList();
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('My First App'),
backgroundColor:new Color(0xFF673AB7),
),
body: new Container(
child: new ListView(
children: cards,
)
)
);
}
}
class QuestionCard extends StatefulWidget {
#override
_QuestionCardState createState() => _QuestionCardState();
}
class _QuestionCardState extends State<QuestionCard> {
#override
Widget build(BuildContext context) {
return Container(
child: Card(
borderOnForeground: true,
color: Colors.green,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
const ListTile(
trailing: Icon(Icons.album),
title: Text('Q1'),
subtitle: Text('What is the name of this location?'),
),
new TextFormField(
decoration: new InputDecoration(
labelText: "Answer Question",
fillColor: Colors.white,
border: new OutlineInputBorder(
borderRadius: new BorderRadius.circular(25.0),
borderSide: new BorderSide(
),
),
//fillColor: Colors.green
),
validator: (val) {
if(val.length==0) {
return "Type your answer here";
}else{
return null;
}
},
keyboardType: TextInputType.text,
style: new TextStyle(
fontFamily: "Poppins",
),
),
ButtonBar(
children: <Widget>[
FlatButton(
child: const Text('Save'),
onPressed: () {/* ... */},
),
],
),
],
),
),
);
}
}
My json is simple (questions.json):
{
"Questions":
[
{
"id" : 1,
"quest" : ["question one"]
},
{
"id" : 2,
"quest" : ["question two", "question three"]
},
{
"id" : 3,
"quest" : ["question four"]
},
{
"id" : 4,
"quest" : ["question five", "question six", "question seven"]
}
]
}
So I have 2 questions I need to solve:
1. If I have more than 1 question I'll need to add an additional text box for a response for which I'll use a different card type, 2, 3, 4 max, which I'll need to define once.
But my real question here:
How do I generate the list based on the json response:
Future _loadQuestionAssets() async
{
return await rootBundle.loadString('assets/questions.json');
}
Future loadQuestion() async{
String jsonString = await _loadQuestionAssets();
final jsonResponse = json.decode(jsonString);
Questions question = new Questions.fromJson(jsonResponse);
//List cards = new List.generate(length, generator)
}
try this:
class MyFirstApp extends StatefulWidget{
#override
createState()=> new _appState();
}
class _appState extends State<MyFirstApp>{
List _displayData;
//assuming that you saved your json file in your assets folder
loadJson() async {
String data = await rootBundle.loadString('assets/json/questions.json');
jsonResult = json.decode(data);
print(jsonResult);
setState((){
_displayData = jsonResult["Questions"];
});
}
#override
void initState(){
super.initState();
loadJson();
}
#override
Widget build(BuildContext context){
return Scaffold(
appbar: Appbar(
title: Text("My APP")
),
body: Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: _displayData == null ? Center(child: CircularProgressIndicator()) :
ListView.builder(
itemcount: _displayData.length,
itembuilder: (context, index){
return Container(
width: MediaQuery.of(context).size.width,
height: 80,
margin: EdgeInsets.only(bottom: 5),
child: Text(_displayData[index]["id"])
);
}
)
)
);
}
}