I have a form where users capture information on multiple textfields. Within the Onchange:, I can see that there's activity every time the user types something on the textfield. However, when I call a method to read the textfield content, the method is not being fired. For example, I call the updateFirstName() method within the OnChange: within the nameController textfield. The method doesn't fire and the App fails when I press Save because the FirstName field is null. Any reason why the updateFirstName method on my code below is not being called? I'm new to Flutter so I might be missing something basic.
import 'dart:ffi';
import 'package:flutter/material.dart';
import '../widgets/main_drawer.dart';
import '../utils/database_helper.dart';
import '../models/customer.dart';
import 'package:intl/intl.dart';
class CustomerDetailsScreen extends StatefulWidget {
static const routeName = '/customer-details';
@override
_CustomerDetailsScreenState createState() => _CustomerDetailsScreenState();
}
class _CustomerDetailsScreenState extends State<CustomerDetailsScreen> {
//Define editing controllers for all the text fields
TextEditingController nameController = TextEditingController();
TextEditingController surnameController = TextEditingController();
TextEditingController cellphoneController = TextEditingController();
TextEditingController emailController = TextEditingController();
//Connecting to the database
DatabaseHelper helper = DatabaseHelper();
//Define some variables
String appBarTitle;
Customer customer; //This is the Customer Model
/*
String sFirstName;
String sSurname;
String sCellNumber;
String sEmailAddress;
String sCompanyName = '-';
*/
var _formKey = GlobalKey<FormState>();
//Method to validate e-mail address
bool validateEmail(String value) {
Pattern pattern =
r'^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$';
RegExp regex = new RegExp(pattern);
return (!regex.hasMatch(value)) ? false : true;
}
@override
Widget build(BuildContext context) {
TextStyle textStyle = Theme.of(context).textTheme.title;
//Populate the text fields
//nameController.text = customer.sFirstName;
//surnameController.text = customer.sSurname;
//cellphoneController.text = customer.sCellNumber;
//emailController.text = customer.sEmailAddress;
return Scaffold(
appBar: AppBar(
title: Text('Edit Customer'),
),
body: GestureDetector(
//Gesture detector wrapped the entire body so we can hide keyboard \
// when user clicks anywhere on the screen
behavior: HitTestBehavior.opaque,
onTap: () {
FocusScope.of(context).requestFocus(new FocusNode());
},
child: Form(
key: _formKey,
child: Padding(
padding: EdgeInsets.only(top: 15.0, left: 10.0, right: 10.0),
child: ListView(
children: <Widget>[
//First Element - Name
Padding(
padding: EdgeInsets.only(top: 15.0, bottom: 15.0),
child: TextFormField(
controller: nameController,
style: textStyle,
textCapitalization: TextCapitalization.words,
validator: (String value) {
if (value.isEmpty) {
return 'Please enter your name';
}
return null;
},
onChanged: (value) {
debugPrint('Something changed on the Name Text Field');
updateFirstName();
},
decoration: InputDecoration(
labelText: 'Name',
labelStyle: textStyle,
errorStyle:
TextStyle(color: Colors.redAccent, fontSize: 15.0),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(5.0),
),
),
),
),
//Second Element - Surname
Padding(
padding: EdgeInsets.only(top: 15.0, bottom: 15.0),
child: TextFormField(
controller: surnameController,
style: textStyle,
textCapitalization: TextCapitalization.words,
validator: (String value) {
if (value.isEmpty) {
return 'Please enter your surname';
}
return null;
},
onChanged: (value) {
debugPrint('Something changed on the Surname Text Field');
updateSurname();
},
decoration: InputDecoration(
labelText: 'Surname',
labelStyle: textStyle,
errorStyle:
TextStyle(color: Colors.redAccent, fontSize: 15.0),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(5.0),
),
),
),
),
//Third Element - Cellphone
Padding(
padding: EdgeInsets.only(top: 15.0, bottom: 15.0),
child: TextFormField(
controller: cellphoneController,
style: textStyle,
keyboardType: TextInputType.number,
validator: (String value) {
if (value.isEmpty) {
return 'Please enter your cellphone number';
} else {
if (value.length < 10)
return 'Cell number must be at least 10 digits';
}
return null;
},
onChanged: (value) {
debugPrint(
'Something changed on the Cellphone Text Field');
updateCellNumber();
},
decoration: InputDecoration(
labelText: 'Cellphone',
labelStyle: textStyle,
errorStyle:
TextStyle(color: Colors.redAccent, fontSize: 15.0),
hintText: 'Enter Cell Number e.g. 0834567891',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(5.0),
),
),
),
),
//Fourth Element - Email Address
Padding(
padding: EdgeInsets.only(top: 15.0, bottom: 15.0),
child: TextFormField(
controller: emailController,
style: textStyle,
keyboardType: TextInputType.emailAddress,
validator: (String value) {
if (value.isEmpty) {
return 'Please enter your e-mail address';
} else {
//Check if email address is valid.
bool validmail = validateEmail(value);
if (!validmail) {
return 'Please enter a valid e-mail address';
}
}
return null;
},
onChanged: (value) {
debugPrint(
'Something changed on the Email Address Text Field');
updateEmailAddress();
},
decoration: InputDecoration(
labelText: 'E-mail',
labelStyle: textStyle,
errorStyle:
TextStyle(color: Colors.redAccent, fontSize: 15.0),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(5.0),
),
),
),
),
//Fifth Element - Row for Save Button
Padding(
padding: EdgeInsets.only(top: 15.0, bottom: 15.0),
child: Row(
children: <Widget>[
Expanded(
child: RaisedButton(
color: Theme.of(context).primaryColorDark,
textColor: Theme.of(context).primaryColorLight,
child: Text(
'Save',
textScaleFactor: 1.5,
),
onPressed: () {
setState(() {
if (_formKey.currentState.validate()) {
debugPrint('Save button clicked');
//Call the Save method only if the validation is passed
_saveCustomerDetails();
}
});
}),
),
],
)),
],
),
),
),
),
);
}
//**********************Updating what is captured by the user on each text field******************/
//Update the sFirstName of the Customer model object
void updateFirstName() {
print('The updateFirstName was called');
customer.sFirstName = nameController.text;
}
//Update the sSurname of the Customer model object
void updateSurname() {
customer.sSurname = surnameController.text;
}
//Update the sCellNumber of the Customer model object
void updateCellNumber() {
customer.sCellNumber = cellphoneController.text;
}
//Update the sEmailAddress of the Customer model object
void updateEmailAddress() {
customer.sEmailAddress = emailController.text;
customer.sCompanyName = '-';
}
//**********************END - Updating what is captured by the user on each text field******************/
//**************************Saving to the Database*************************************/
void _saveCustomerDetails() async {
//moveToLastScreen();
//Update the dtUpdated of the Customer model with current time (Confirm that it is GMT)
print('Trying to save customer info was called');
customer.dtUpdated = DateFormat.yMMMd().format(DateTime.now());
print('Trying to save customer info was called - 2');
int result;
result = await helper.insertNewHumanCustomer(customer);
if (result != 0) {
//Saving was a Success
_showAlertDialog('Success', 'Customer details saved successfully');
print('The customer details were saved successfully');
} else {
//Saving was a Failure
print('FAILURE - The customer details failed to save');
_showAlertDialog('Failure', 'Oopsy.....something went wrong. Try again');
}
}
//*****Show Alert Popup message*****/
void _showAlertDialog(String title, String message) {
AlertDialog alertDialog = AlertDialog(
title: Text(title),
content: Text(message),
);
showDialog(context: context, builder: (_) => alertDialog);
}
//*****END - Show Alert Popup message*****/
//**************************Saving to the Database*************************************/
}