The method 'changeeventdescription' was called on null - flutter

I have looked at many answers to other questions but I think I am missing something still. I am developing a flutter app and the page that I am having trouble with is a page where I create meetings for a calendar.
When I look at the debug log I see that the eventProvider is null. I copied the structure from another screen in my app and everything works fine there. What have I missed?
Here is the code from the screen:
final eventRef = FirebaseFirestore.instance.collection(('events'));
class AddEventScreen extends StatefulWidget {
static const String id = 'add_event_screen';
final Event event;
AddEventScreen([this.event]);
#override
_AddEventScreenState createState() => _AddEventScreenState();
}
class _AddEventScreenState extends State<AddEventScreen> {
final _db = FirebaseFirestore.instance;
final eventNameController = TextEditingController();
final eventStartTimeController = TextEditingController();
final eventDurationController = TextEditingController();
final eventDateController = TextEditingController();
final eventDescriptionController = TextEditingController();
#override
void dispose() {
eventNameController.dispose();
eventStartTimeController.dispose();
eventDurationController.dispose();
eventDateController.dispose();
eventDescriptionController.dispose();
super.dispose();
}
bool showSpinner = false;
String eventName;
String eventStartTime;
String eventDuration;
String eventData;
String eventDescription;
getCurentAgencyEvents() async {
if (globals.agencyId == null) {
eventNameController.text = "";
eventStartTimeController.text = "";
eventDurationController.text = "";
eventDateController.text = "";
eventDescriptionController.text = "";
} else {
final DocumentSnapshot currentEvent =
await eventRef.doc(globals.agencyId).get();
// existing record
// Updates Controllers
eventNameController.text = currentEvent.data()["name"];
eventStartTimeController.text = currentEvent.data()['address1'];
eventDurationController.text = currentEvent.data()['address2'];
eventDateController.text = currentEvent.data()['city'];
eventDescriptionController.text = currentEvent.data()['state'];
// Updates State
new Future.delayed(Duration.zero, () {
final eventProvider =
Provider.of<EventProvider>(context, listen: false);
eventProvider.loadValues(widget.event);
});
}
}
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
final eventProvider = Provider.of<EventProvider>(context);
final _firestoreService = FirestoreService();
DateTime _date = new DateTime.now();
TimeOfDay _time = new TimeOfDay.now();
Duration initialtimer = new Duration();
DateTime _selectedDate = DateTime.now();
TimeOfDay _timePicked = TimeOfDay.now();
return Scaffold(
appBar: AppBar(
title: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image.asset('assets/images/Appbar_logo.png',
fit: BoxFit.cover, height: 56),
],
),
),
backgroundColor: Colors.white,
body: SafeArea(
child: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
children: <Widget>[
Text(
'Event Editor',
style: TextStyle(
fontSize: 30,
fontWeight: FontWeight.w800,
),
),
SizedBox(
height: 30.0,
),
TextField(
controller: eventNameController,
keyboardType: TextInputType.text,
textAlign: TextAlign.center,
onChanged: (value) {
eventProvider.changeeventname(value);
},
decoration: kTextFieldDecoration.copyWith(
hintText: 'Event Name', labelText: 'Event Name'),
),
SizedBox(
height: 8.0,
),
TextField(
controller: eventDurationController,
textAlign: TextAlign.center,
onChanged: (value) {
eventProvider.changeeventduration(value);
},
decoration: kTextFieldDecoration.copyWith(
hintText: 'Duration', labelText: 'Duration'),
),
SizedBox(
height: 8.0,
),
TextField(
controller: eventDateController,
keyboardType: TextInputType.datetime,
textAlign: TextAlign.center,
onTap: () async {
DateTime _datePicked = await showDatePicker(
context: context,
initialDate: _selectedDate,
//firstDate: new DateTime.now().add(Duration(days: -365)),
firstDate: new DateTime(2020),
lastDate: new DateTime(2022));
if (_date != null && _date != _datePicked) {
setState(() {
eventDateController.text =
DateFormat("MM/dd/yyyy").format(_datePicked);
eventProvider.changeeventdate(_datePicked);
_selectedDate = _datePicked;
//DateFormat("MM/dd/yyyy").format(_date));
});
}
},
onChanged: (value) {
eventProvider.changeeventdate(_date);
},
decoration: kTextFieldDecoration.copyWith(
hintText: 'Date',
labelText: 'Date',
),
),
SizedBox(
height: 8.0,
),
TextField(
controller: eventStartTimeController,
keyboardType: TextInputType.text,
textAlign: TextAlign.center,
onTap: () async {
TimeOfDay _timePicked = await showTimePicker(
context: context,
initialTime: new TimeOfDay.now());
//if (_timePicked != null) {
setState(() {
eventStartTimeController.text = _timePicked.format(context);
});
//}
},
onChanged: (value) {
eventProvider.changeeventstarttime(_timePicked);
},
decoration: kTextFieldDecoration.copyWith(
hintText: 'Start Time',
labelText: 'Start Time',
),
),
SizedBox(
height: 8.0,
),
TextField(
controller: eventDescriptionController,
keyboardType: TextInputType.text,
textAlign: TextAlign.center,
onChanged: (value) {
eventProvider.changeeventdescription(value);
},
decoration: kTextFieldDecoration.copyWith(
hintText: 'Description', labelText: 'Description'),
),
SizedBox(
height: 8.0,
),
RoundedButton(
title: 'Save Event',
colour: Colors.blueAccent,
onPressed: () async {
setState(() {
showSpinner = true;
});
try {
globals.newEvent = true;
eventProvider.saveEvent();
Navigator.of(context).pushReplacement(MaterialPageRoute(
builder: (context) => AppointmentCalendarScreen()));
setState(() {
showSpinner = false;
});
} catch (e) {
// todo: add better error handling
print(e);
}
},
),
SizedBox(
height: 8.0,
),
(widget != null)
? RoundedButton(
title: 'Delete',
colour: Colors.red,
onPressed: () async {
setState(() {
showSpinner = true;
});
try {
//agencyProvider.deleteAgency(globals.currentUid);
Navigator.of(context).pushReplacement(MaterialPageRoute(
builder: (context) => AppointmentCalendarScreen()));
setState(() {
showSpinner = false;
});
} catch (e) {
// todo: add better error handling
print(e);
}
},
)
: Container()
],
),
),
),
),
);
}
}
Here is the debug log and I get the same message for each input control:
======== Exception caught by widgets ===============================================================
The following NoSuchMethodError was thrown while calling onChanged:
The method 'changeeventname' was called on null.
Receiver: null
Tried calling: changeeventname("Test event")
Here is the code for the EventProvider:
class EventProvider with ChangeNotifier {
final firestoreService = FirestoreService();
FirebaseFirestore _db = FirebaseFirestore.instance;
final eventRef = FirebaseFirestore.instance.collection(('events'));
String _eventName;
TimeOfDay _eventStartTime;
String _eventDuration;
DateTime _eventDate;
String _eventDescription;
//Getters
String get eventName => _eventName;
TimeOfDay get eventStartTime => _eventStartTime;
String get eventDuration => _eventDuration;
DateTime get eventDate => _eventDate;
String get eventDescription => _eventDescription;
final EventProvider eventProvider = new EventProvider();
//Setters
changeeventname(String value) {
_eventName = value;
notifyListeners();
}
changeeventstarttime(TimeOfDay value) {
_eventStartTime = value;
notifyListeners();
}
changeeventduration(String value) {
_eventDuration = value;
notifyListeners();
}
changeeventdate(DateTime value) {
_eventDate = value;
notifyListeners();
}
changeeventdescription(String value) {
_eventDescription = value;
notifyListeners();
}
loadValues(Event event) {
_eventName = event.eventName;
_eventStartTime = event.eventStartTime;
_eventDuration = event.eventDuration;
_eventDate = event.eventDate;
_eventDescription = event.eventDescription;
}
saveEvent() {
var newEvent = Event(
eventName: _eventName,
eventStartTime: _eventStartTime,
eventDuration: _eventDuration,
eventDate: _eventDate,
eventDescription: _eventDescription);
// If the agency is a new agency retrieve the agency
// document ID and save it to a new agent document
if (globals.newEvent == true) {
String id = _db.collection('event').doc().id;
globals.agencyId = id;
//firestoreService.saveNewEvent(newEvent);
eventProvider.saveEvent();
globals.newEvent = false;
} else {
firestoreService.saveEvent(newEvent);
}
}
}

I found the issue. I just needed to clean up the code.

Related

Image uploads in Firebase but not the data fetched from TextFormFields and dropdownbutton

Flutter beginner here. Working on a flutter project where I can submit a form where I can upload it's content in firebase. I took the data from TextFormField and DropDownButton and the images from ImagePicker. I can upload the image file perfectly to the firebase but the data are not uploading. Here is the code:
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_storage/firebase_storage.dart';
import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:image_picker/image_picker.dart';
import 'package:path/path.dart' as path;
class AddDoctor extends StatefulWidget {
#override
State<AddDoctor> createState() => AddDoctorState();
}
class AddDoctorState extends State<AddDoctor> {
late String name;
late int age;
late String description;
String specialistValue = 'Select Specialist';
String hospitalValue = 'Select Hospital';
List<String> imageUrlList = [];
final controllerName = TextEditingController();
final controllerAge = TextEditingController();
final controllerDesciption = TextEditingController();
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
final FirebaseStorage _firebaseStorage = FirebaseStorage.instance;
final FirebaseFirestore _firestore = FirebaseFirestore.instance;
final ImagePicker _picker = ImagePicker();
XFile? image;
void pickDoctorImage() async {
try {
final pickedImage = await _picker.pickImage(source: ImageSource.gallery);
setState(() {
image = pickedImage!;
});
} catch (e) {}
}
Widget displayImage() {
return Image.file(File(image!.path));
}
Future<void> uploadImage() async {
Reference ref =
_firebaseStorage.ref('products/${path.basename(image!.path)}');
await ref.putFile(File(image!.path)).whenComplete(() async {
await ref.getDownloadURL().then((value) {
imageUrlList.add(value);
});
});
}
void uploadInfo() async {
CollectionReference infoRef = _firestore.collection('DoctorList');
await infoRef.doc().set({
'name': name,
'age': age,
'description': description,
'specialist': specialistValue,
'hospital': hospitalValue,
'doctorImage': imageUrlList,
}).whenComplete(() {
Navigator.pop(context);
});
}
void uploadDoctorInfo() async {
await uploadImage().whenComplete(() => uploadInfo);
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color(0xFFD9E4EE),
appBar: AppBar(
title: const Text('Add Doctor'),
actions: [
IconButton(
icon: const Icon(Icons.menu),
onPressed: () {},
),
],
),
body: Form(
key: _formKey,
child: ListView(
padding: const EdgeInsets.all(16),
children: <Widget>[
TextFormField(
keyboardType: TextInputType.name,
validator: (value) {
if (value!.isEmpty) {
return 'Please Name must not be empty';
} else {
return null;
}
},
controller: controllerName,
decoration: const InputDecoration(
label: Text('Name'),
),
onSaved: (value) {
name = value!;
},
),
const SizedBox(height: 10),
TextFormField(
keyboardType: TextInputType.number,
validator: (value) {
if (value!.isEmpty) {
return 'Please Age must not be empty';
} else {
return null;
}
},
controller: controllerAge,
decoration: const InputDecoration(
label: Text('Age'),
),
onSaved: (value) {
age = int.parse(value!);
},
),
const SizedBox(height: 10),
DropdownButton(
borderRadius: BorderRadius.circular(30),
value: specialistValue,
items: specialistList.map<DropdownMenuItem<String>>((e) {
return DropdownMenuItem(
value: e,
child: Text(e),
);
}).toList(),
onChanged: (String? value) {
setState(() {
specialistValue = value!;
});
},
),
DropdownButton(
borderRadius: BorderRadius.circular(30),
value: hospitalValue,
items: hospitalList.map<DropdownMenuItem<String>>((e) {
return DropdownMenuItem(
value: e,
child: Text(e),
);
}).toList(),
onChanged: (String? value) {
setState(() {
hospitalValue = value!;
});
},
),
const SizedBox(height: 10),
TextFormField(
keyboardType: TextInputType.number,
validator: (value) {
if (value!.isEmpty) {
return 'Please Description must not be empty';
} else {
return null;
}
},
maxLength: 100,
maxLines: 3,
controller: controllerDesciption,
decoration: const InputDecoration(
label: Text('Description'),
),
onChanged: (value) {
description = value;
},
),
const SizedBox(height: 10),
// CircleAvatar(
// radius: 50,
// backgroundImage: image != null ? FileImage(image) : null,
// ),
InkWell(
onTap: () {
setState(() {
image = null;
});
},
child: Container(
padding: const EdgeInsetsDirectional.only(top: 60),
height: 150,
width: 150,
decoration: const BoxDecoration(
color: Colors.blue,
shape: BoxShape.circle,
),
child: Center(
child: image != null
? displayImage()
: const Text(
'You have not pick any image',
style: TextStyle(fontSize: 11),
textAlign: TextAlign.center,
),
)),
),
const SizedBox(height: 10),
ElevatedButton(
onPressed: () {
pickDoctorImage();
},
child: const Text('Upload Image'),
),
const SizedBox(height: 10),
ElevatedButton(
child: const Text('Submit'),
onPressed: () {
uploadDoctorInfo();
},
),
],
),
),
);
}
}
There aren't any error in the file either. I can't figure out where the source of the problem is.
Fixed it. The problem was in
void uploadDoctorInfo() async {
await uploadImage().whenComplete(() => uploadInfo);
}
I changed it to
void uploadDoctorInfo() async {
await uploadImage().whenComplete(uploadInfo);
}
And now it's working fine
You should add for the new entry instead set data in collection. Try using the following code
void uploadInfo() async {
CollectionReference infoRef = _firestore.collection('DoctorList');
await infoRef.add({
'name': name,
'age': age,
'description': description,
'specialist': specialistValue,
'hospital': hospitalValue,
'doctorImage': imageUrlList,
}).whenComplete(() {
Navigator.pop(context);
});
}
Edited
Your are referencing uploadInfo function instead of call that. updateInfo should be called by adding (), so uploadDoctorInfo will be look like.
void uploadDoctorInfo() async {
await uploadImage().whenComplete(() => uploadInfo());
}
or
void uploadDoctorInfo() async {
await uploadImage().whenComplete(uploadInfo);
}

Return null value between two dates in sqflite and flutter

i have spent three days for find solution but nothing , always have a same value NULL!
I create database and the function to calculate total in chossing period here :
1/ class Database
class DatabaseHelper {
static DatabaseHelper _databaseHelper; // Singleton DatabaseHelper
static Database _database; // Singleton Database
String clientTable = 'client_table';
String colId = 'id';
String colNumerotelephone = 'numerotelephone';
String colCode = 'code';
String colPrix = 'prix';
String colPriority = 'priority';
String colColor = 'color';
String colDate = 'date';
DatabaseHelper._createInstance(); // Named constructor to create instance of DatabaseHelper
factory DatabaseHelper() {
if (_databaseHelper == null) {
_databaseHelper = DatabaseHelper
._createInstance(); // This is executed only once, singleton object
}
return _databaseHelper;
}
Future<Database> get database async {
if (_database == null) {
_database = await initializeDatabase();
}
return _database;
}
Future<Database> initializeDatabase() async {
Directory directory = await getApplicationDocumentsDirectory();
String path = directory.path + 'clients.db';
var clientsDatabase =
await openDatabase(path, version: 1, onCreate: _createDb);
return clientsDatabase;
}
void _createDb(Database db, int newVersion) async {
await db.execute(
'CREATE TABLE $clientTable($colId INTEGER PRIMARY KEY AUTOINCREMENT, $colNumerotelephone TEXT,$colCode TEXT, '
'$colPrix REAL, $colPriority INTEGER, $colColor INTEGER,$colDate TEXT)');
}
.......
// code where i get the null value
Future claculTotalPeriod (String startDate, String endDate) async {
var totalClientperiod = await database;
var resulttotalperiod = await totalClientperiod.rawQuery("SELECT SUM($colPrix) AS TOTAL from $clientTable WHERE $colDate BETWEEN '$startDate' AND '$endDate'");
return resulttotalperiod.toList();
}
}
2/and this class for displaying database data
class ClientList extends StatefulWidget {
const ClientList({Key key}) : super(key: key);
#override
State<StatefulWidget> createState() {
return ClientListState();
}
}
class ClientListState extends State<ClientList> {
DatabaseHelper databaseHelper = DatabaseHelper();
List<Client> clientList;
double somme_period = 00;
String somme_total_period = "00.00";
String startDate='';
String endDate='';
TextEditingController startdate = TextEditingController();
TextEditingController finishdate = TextEditingController();
void calcul_total_period() async {
var totalSumPeriod = (await databaseHelper.claculTotalPeriod(startDate, endDate))[0]['TOTAL']; //['$startDate''$endDate'];
setState(() {
somme_period = totalSumPeriod ?? 00;
somme_total_period = somme.toStringAsFixed(2);
});
}
#override
Widget build(BuildContext context) {
if (clientList == null) {
clientList = [];
updateListView();
}
return Scaffold(
appBar: myAppBar(),
body: clientList.isEmpty
? Container(
color: Colors.white,
child: Center(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Text('ADD Client',
style: Theme.of(context).textTheme.bodyText2),
),
),
)
: Container(
color: Colors.white,
child: getClientsList(),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
navigateToDetail(Client('', '', '', 3, 0, 0.0), 'new');
},
tooltip: 'Add',
shape: const CircleBorder(
side: BorderSide(color: Colors.black, width: 2.0)),
child: const Icon(Icons.add, color: Colors.black),
backgroundColor: Colors.white,
),
bottomNavigationBar: OutlinedButton(
onPressed: () {
showDialog(
context: context,
builder: (context) {
return Container(
margin: const EdgeInsets.all(20),
child: Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
color: Colors.white,
clipBehavior: Clip.antiAliasWithSaveLayer,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
const SizedBox(height: 20,),
TextField(
controller: startdate,
//editing controller of this TextField
decoration: const InputDecoration(
icon: Icon(Icons.calendar_today), //icon of text field
labelText: "start date" //label text of field
),
readOnly: true,
//set it true, so that user will not able to edit text
onTap: () async {
DateTime pickedDate = await showDatePicker(
context: context,
initialDate: DateTime.now(),
firstDate: DateTime(2022,12),
lastDate: DateTime(2026,12));
if (pickedDate != null) {
print(
pickedDate); //pickedDate output format => 2021-03-10 00:00:00.000
String formattedDate =
DateFormat('yyyy-MM-dd').format(pickedDate);
print(
formattedDate); //formatted date output using intl package => 2021-03-16
setState(() {
startdate.text =
formattedDate;
startDate = startdate.text.toString(); //set output date to TextField value.
});
} else {}
},
),
const SizedBox(height: 20,),
TextField(
controller: finishdate,
//editing controller of this TextField
decoration: const InputDecoration(
icon: Icon(Icons.calendar_today), //icon of text field
labelText: "end date" //label text of field
),
readOnly: true,
//set it true, so that user will not able to edit text
onTap: () async {
DateTime pickedDate = await showDatePicker(
context: context,
initialDate: DateTime.now(),
firstDate: DateTime(2022,12),
lastDate: DateTime(2026,12));
if (pickedDate != null) {
print(
pickedDate); //pickedDate output format => 2021-03-10 00:00:00.000
String formattedDate =
DateFormat('yyyy-MM-dd').format(pickedDate);
print(
formattedDate); //formatted date output using intl package => 2021-03-16
setState(() {
finishdate.text =
formattedDate; //set output date to TextField value.
endDate = finishdate.text.toString();
});
} else {}
},
),
const SizedBox(height: 20,),
OutlinedButton(
onPressed: () {
calcul_total_period();
},
child: const Text(' period total')),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
somme_total_period,
style: Theme.of(context).textTheme.headline5,
textAlign: TextAlign.center,
),
),
],
),
),
);
});
},
child: const Text('totalinperiod')),
);
}
void updateListView() {
final Future<Database> dbFuture = databaseHelper.initializeDatabase();
dbFuture.then((database) {
Future<List<Client>> clientListFuture = databaseHelper.getClientList();
clientListFuture.then((clientList) {
setState(() {
this.clientList = clientList;
count = clientList.length;
});
});
});
}
}
when i execute the code always i get the null value for the resulttotalperiod
can same one help me please.

how to hide email field when a user logged with phone authentication in flutter firebase?

i have an buying and selling app in which a user can sign up with different methods like google, phone authentication and email so my question is when a user log in with phone authentication how to hide the email field from user profile.
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:mobihub_2/Screens/email_verifcation_screen.dart';
import 'package:mobihub_2/Screens/search_screens/search_filter.dart';
import '../../Models/user_model.dart';
import '../home_page.dart';
class ProfileDetailScreen extends StatefulWidget {
final String? name;
final String? email;
final String? location;
final String? gender;
final bool number;
const ProfileDetailScreen(
{Key? key, required this.name, this.email, this.location, required this.gender,required this.number})
: super(key: key);
#override
State<ProfileDetailScreen> createState() => _ProfileDetailScreenState();
}
class _ProfileDetailScreenState extends State<ProfileDetailScreen> {
final _auth=FirebaseAuth.instance;
var collectionRef = FirebaseFirestore.instance.collection('UsersDetails');
var dropDownValue;
bool loading = false;
var name = TextEditingController();
var emailC = TextEditingController();
var passwordC =TextEditingController();
var city = TextEditingController();
#override
void initState() {
if (widget.location != null && widget.location!.isNotEmpty) {
setState(() {
city = TextEditingController(text: widget.location);
});
}
if (widget.name != null && widget.name!.isNotEmpty) {
setState(() {
name = TextEditingController(text: widget.name);
});
}
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.amberAccent,
foregroundColor: Colors.blueGrey,
title: Text('Profile'),
elevation: 0,
),
body: SafeArea(
child: Padding(
padding: EdgeInsets.all(20),
child: Column(
children: [
TextFormField(
onChanged: (value) {
setState(() {
name = TextEditingController(text: (value));
});
},
initialValue: name.text,
decoration: InputDecoration(
hintText: 'Name',
prefixIcon: Icon(Icons.person_outline_outlined),
suffixIcon: Icon(Icons.edit_outlined),
),
),
SizedBox(
height: 20,
),
TextFormField(
onTap: (){
showDialog(context: context, builder: (context) {
return AlertDialog(
content: Text('Want to change your email?'),
actions: [
Padding(padding:EdgeInsets.all(10),
child: Column(
children: [
TextFormField(
controller:emailC,
decoration: InputDecoration(
hintText: 'new email',
prefixIcon: Icon(Icons.email_outlined),
),
),
SizedBox(height: 10,),
TextFormField(
controller: passwordC,
decoration: InputDecoration(
hintText: 'old Password',
prefixIcon: Icon(Icons.lock_open_outlined),
),
),
SizedBox(height: 5,),
ElevatedButton(onPressed: ()async{
loading=true;
await changeEmail(
email: emailC.text,password: passwordC.text
);
loading=false;
}, child:loading?Center(child: CircularProgressIndicator(color:Colors.black,),): Text('Submit'))
],
),
)
],
);
}
);
},
readOnly: true,
initialValue: widget.email,
// onChanged: (value) {
// setState(() {
// email = value;
// });
// },
decoration: InputDecoration(
hintText: 'Email',
prefixIcon: Icon(Icons.email_outlined),
suffixIcon: IconButton(onPressed: () {
}, icon: Icon(Icons.edit_outlined),),
),
),
SizedBox(
height: 20,
),
TextFormField(
readOnly: true,
initialValue: widget.number.toString(),
decoration: InputDecoration(
hintText: 'Phone number',
prefixIcon: Icon(Icons.email_outlined),
suffixIcon: IconButton(onPressed: () {
}, icon: Icon(Icons.edit_outlined),),
),
),
SizedBox(
height: 20,
),
TextFormField(
onTap: (){
setState(() async {
city.text = await Navigator.push(context,
MaterialPageRoute(builder: (_) => SearchScreen()));
});
},
readOnly: true,
controller: city,
decoration: InputDecoration(
hintText: 'Address',
prefixIcon: Icon(Icons.location_city_outlined),
suffixIcon: IconButton(onPressed: () {
}, icon: Icon(Icons.arrow_drop_down_circle_outlined)),
),
),
SizedBox(
height: 20,
),
DropdownButtonFormField(
decoration: InputDecoration(
prefixIcon: Icon(Icons.person,),
),
hint: Text(widget.gender!.isNotEmpty
? widget.gender!
: 'Select Gender'),
items: ['Male', 'Female'].map(
(val) {
return DropdownMenuItem<String>(
value: val,
child: Text(val),
);
},
).toList(), onChanged: (String? val) {
setState(
() {
dropDownValue = val;
},
);
},),
SizedBox(
height: 20,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
OutlinedButton(onPressed: () {}, child: Text('Cancel')),
OutlinedButton(
style: OutlinedButton.styleFrom(
backgroundColor: Colors.amberAccent),
onPressed: () async {
setState(() {
loading = true;
});
await postDetailsToFirestore();
setState(() {
loading = false;
});
},
child: loading
? Center(
child: CircularProgressIndicator(color: Colors.blue,))
: Text('Save')),
],
),
],
),
),
),
);
}
Future<void> changeEmail(
{required String email, required String password}) async {
//showLoadingDialog(message: AppTexts.updating);
try {
User user = _auth.currentUser!;
DocumentReference ref=collectionRef.doc(user.uid);
final cred =
EmailAuthProvider.credential(email: user.email!, password: passwordC.text);
user.reauthenticateWithCredential(cred).then((value) {
user.updateEmail(email).then((_) async {
await ref.update({'email': email}).then((value) async {
// go to root page
await _auth.currentUser!.sendEmailVerification();
Fluttertoast.showToast(msg: 'Verification Email has been sent to you');
await _auth.signOut();
});
setState(() {
Navigator.pushAndRemoveUntil(context, MaterialPageRoute(builder: (_)=>VerificationScreen()), (route) => false);
});
}).catchError((error) {
Fluttertoast.showToast(msg: error.toString());
});
}).catchError((err) {
Fluttertoast.showToast(msg: err.toString());
});
} on Exception catch (err) {
Fluttertoast.showToast(msg: err.toString());
// showErrorDialog(err.toString());
}
}
postDetailsToFirestore() async {
var auth = FirebaseAuth.instance;
FirebaseFirestore firebaseFirestore = FirebaseFirestore.instance;
User? user = auth.currentUser;
UserModel userModel = UserModel();
// writing all the values
userModel.email = user!.email;
userModel.uid = user.uid;
userModel.fullName = name.text;
userModel.phone = user.phoneNumber;
userModel.location = city.text;
userModel.joindate = '';
userModel.gender = dropDownValue;
await firebaseFirestore
.collection("UsersDetails")
.doc(user.uid)
.update(userModel.toMap());
Fluttertoast.showToast(msg: "Account Updated successfully :) ");
Navigator.pushAndRemoveUntil(
(context),
MaterialPageRoute(builder: (context) => const Home()),
(route) => false);
}
}
when a user login with email the phone field will hide and when user login with phone the email field will hide. If anybody can help me it would be very appreciable.Thank you

start date and end date validation in Flutter

In the below code I need to put validation like if the startdate is null give error to user or display the date chosen. I'm not sure how to do it.
String _displayText(String begin, DateTime? date) {
if (date != null) {
return '$begin Date: ${date.toString().split(' ')[0]}';
} else {
return 'Choose The Date';
}
}
In the below it will display the date
Text(
_displayText('Start', startdate),
style: const TextStyle(
fontWeight: FontWeight.bold, fontSize: 15, color: Colors.black),
),
To validate the date, we are checking the date and controlling validator using date not text. Like
String? endDateValidator(value) {
if (startDate != null && endData == null) {
return "select Both data";
}
if (endData == null) return "select the date";
if (endData!.isBefore(startDate!)) {
return "End date must be after startDate";
}
return null; // optional while already return type is null
}
Inside the form TextFormFiled will be
TextFormField(
controller: endDateController,
readOnly: true,
decoration: const InputDecoration(
hintText: 'Choose The Date',
),
onTap: () async {
endData = await pickDate();
endDateController.text = _displayText("start", endData);
setState(() {});
},
validator: endDateValidator,
),
Test on DartPad.
Widget to play
class DateValidationInForm extends StatefulWidget {
DateValidationInForm({Key? key}) : super(key: key);
#override
State<DateValidationInForm> createState() => _DateValidationInFormState();
}
class _DateValidationInFormState extends State<DateValidationInForm> {
/// more about validation https://docs.flutter.dev/cookbook/forms/validation
final _formKey = GlobalKey<FormState>();
String _displayText(String begin, DateTime? date) {
if (date != null) {
return '$begin Date: ${date.toString().split(' ')[0]}';
} else {
return 'Choose The Date';
}
}
final TextEditingController startDateController = TextEditingController(),
endDateController = TextEditingController();
DateTime? startDate, endData;
Future<DateTime?> pickDate() async {
return await showDatePicker(
context: context,
initialDate: DateTime.now(),
firstDate: DateTime(1999),
lastDate: DateTime(2999),
);
}
String? startDateValidator(value) {
if (startDate == null) return "select the date";
}
String? endDateValidator(value) {
if (startDate != null && endData == null) {
return "select Both data";
}
if (endData == null) return "select the date";
if (endData!.isBefore(startDate!)) {
return "End date must be after startDate";
}
return null; // optional while already return type is null
}
#override
Widget build(BuildContext context) {
return Form(
key: _formKey,
child: Column(
children: [
TextFormField(
controller: startDateController,
decoration: const InputDecoration(
hintText: 'Choose The Date',
),
onTap: () async {
startDate = await pickDate();
startDateController.text = _displayText("start", startDate);
setState(() {});
},
readOnly: true,
validator: startDateValidator,
style: const TextStyle(
fontWeight: FontWeight.bold, fontSize: 15, color: Colors.black),
),
TextFormField(
controller: endDateController,
readOnly: true,
decoration: const InputDecoration(
hintText: 'Choose The Date',
),
onTap: () async {
endData = await pickDate();
endDateController.text = _displayText("start", endData);
setState(() {});
},
validator: endDateValidator,
style: const TextStyle(
fontWeight: FontWeight.bold, fontSize: 15, color: Colors.black),
),
ElevatedButton(
onPressed: () {
_formKey.currentState?.validate();
},
child: Text("submit"),
)
],
),
);
}
}
Check cookbook/forms/validation to learn more.

Flutter: How to assign other value (object) as Text Editing Controller in Another Field?

I'm building a form that has contact name and phone number fields. User will be able to choose (tap) contact from previously saved contact list, and this should display name and phone numbers at their respective fields.
To achieve that I'm using TypeAheadFormField from Flutter_Form_Builder Package version: 3.14.0 to build my form.
I successfully assign _nameController from local database in the default TypeAheadFormField controller.
But I can't assign _mobileController from the same choice I tapped to FormBuilderTextField.
I managed to get "name'-value with TypeAheadFormField, but everytime I switch the choices from suggestions,
the _mobileController.text didn't update on FormBuilderTextField
My code as follow:
import 'package:myApp/customer.dart';
import 'package:myApp/db_helper.dart';
import 'package:flutter/material.dart';
import 'package:flutter_form_builder/flutter_form_builder.dart';
class MyForm extends StatefulWidget {
#override
_MyFormState createState() => _MyFormState();
}
class _MyFormState extends State<MyForm> {
DatabaseHelper _dbHelper;
Customer _customer = Customer();
List<Customer> _customerList = [];
final _formKey = GlobalKey<FormBuilderState>();
final _cfKey = GlobalKey<FormBuilderState>();
final _nameController = TextEditingController();
final _inputContactNameController = TextEditingController();
final _inputContactPhoneController = TextEditingController();
var _mobileController = TextEditingController();
#override
void initState() {
super.initState();
_refreshBikeSellerList();
setState(() {
_dbHelper = DatabaseHelper.instance;
});
_mobileController = TextEditingController();
_mobileController.addListener(() {
setState(() {});
});
}
#override
void dispose() {
_mobileController.dispose();
_nameController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Container(
child: FormBuilder(
key: _formKey,
child: Column(
children: [
FormBuilderTypeAhead(
attribute: 'contact_person',
initialValue: _customer,
controller: _nameController,
onChanged: (val) {},
itemBuilder: (context, Customer _customer) {
return ListTile(
title: Text(_customer.name),
subtitle: Text(_customer.mobile),
);
},
selectionToTextTransformer: (Customer c) => c.name,
suggestionsCallback: (query) {
if (query.isNotEmpty) {
var lowercaseQuery = query.toLowerCase();
return _customerList.where((_customer) {
return _customer.name
.toLowerCase()
.contains(lowercaseQuery);
}).toList(growable: false)
..sort((a, b) => a.name
.toLowerCase()
.indexOf(lowercaseQuery)
.compareTo(
b.name.toLowerCase().indexOf(lowercaseQuery)));
} else {
return _customerList;
}
},
textFieldConfiguration: TextFieldConfiguration(
autofocus: true,
style: DefaultTextStyle.of(context).style.copyWith(
fontSize: 17,
letterSpacing: 1.2,
color: Colors.black,
fontWeight: FontWeight.w300,
),
// controller: guessMotor1,
),
onSuggestionSelected: (val) {
if (val != null) {
return _customerList.map((_customer) {
setState(() {
_mobileController.text = _customer.mobile;
});
}).toList();
} else {
return _customerList;
}
},
),
FormBuilderTextField(
controller: _mobileController,
attribute: 'mobile',
readOnly: true,
style: TextStyle(fontSize: 17),
decoration: InputDecoration(
hintText: 'mobile',
),
),
SizedBox(height: 40),
Container(
child: RaisedButton(
onPressed: () async {
await manageContact(context);
},
child: Text('Manage Contact'),
),
),
],
),
),
);
}
manageContact(BuildContext context) async {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text(
'Manage Contact',
textAlign: TextAlign.center,
),
titleTextStyle: TextStyle(
fontWeight: FontWeight.w500,
fontSize: 17,
color: Colors.black45,
letterSpacing: 0.8),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(12))),
content: FormBuilder(
key: _cfKey,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
// SizedBox(height: 10),
InkResponse(
onTap: () {},
child: CircleAvatar(
radius: 30,
child: Icon(
Icons.person_add,
color: Colors.grey[100],
),
backgroundColor: Colors.grey[500],
),
),
SizedBox(height: 10),
Container(
width: MediaQuery.of(context).size.width * 0.5,
margin: EdgeInsets.symmetric(horizontal: 15),
child: FormBuilderTextField(
maxLength: 20,
controller: _inputContactNameController,
textAlign: TextAlign.start,
keyboardType: TextInputType.text,
textCapitalization: TextCapitalization.words,
attribute: 'contact_person',
decoration: InputDecoration(
prefixIcon: Icon(
Icons.person_outline,
size: 22,
)),
onChanged: (val) {
setState(() {
_customer.name = val;
_formKey
.currentState.fields['contact_person'].currentState
.validate();
});
},
autovalidateMode: AutovalidateMode.always,
validators: [
FormBuilderValidators.required(),
FormBuilderValidators.maxLength(20),
FormBuilderValidators.minLength(2),
],
),
),
Container(
width: MediaQuery.of(context).size.width * 0.5,
margin: EdgeInsets.symmetric(horizontal: 15),
child: FormBuilderTextField(
attribute: 'phone_number',
controller: _inputContactPhoneController,
textAlign: TextAlign.start,
keyboardType: TextInputType.number,
decoration: InputDecoration(
prefixIcon: Icon(
Icons.phone_android,
size: 22,
)),
onChanged: (val) {
setState(() {
_customer.mobile = val;
_formKey.currentState.fields['phone_number'].currentState
.validate();
});
},
validators: [
FormBuilderValidators.required(),
FormBuilderValidators.numeric(),
],
valueTransformer: (text) {
return text == null ? null : num.tryParse(text);
},
),
),
SizedBox(height: 20),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
RaisedButton(
color: Colors.white,
child: Text('Cancel'),
onPressed: () {
Navigator.of(context).pop();
}),
RaisedButton(
color: Colors.grey[400],
child: Text(
'Save',
style: TextStyle(color: Colors.white),
),
onPressed: () async {
try {
if (_formKey.currentState.validate()) {
_formKey.currentState.save();
if (_customer.id == null)
await _dbHelper.insertBikeContact(_customer);
else
await _dbHelper.updateCustomer(_customer);
_refreshBikeSellerList();
_formKey.currentState.reset();
_inputContactNameController.clear();
_inputContactPhoneController.clear();
Navigator.of(context).pop();
}
} catch (e) {
print(e);
}
},
)
],
),
],
),
),
),
);
}
_refreshBikeSellerList() async {
List<Customer> x = await _dbHelper.getCustomer();
setState(() {
_customerList = x;
});
}
}
Is there any possible way to update _mobileController as I tap?
Any help would be much appreciated.
Thank you in advance.
EDITED:
class where I save the customer data:
class Customer {
int id;
String name;
String mobile;
static const tblCustomer = 'Customer';
static const colId = 'id';
static const colName = 'name';
static const colMobile = 'mobile';
Customer({
this.id,
this.name,
this.mobile,
});
Map<String, dynamic> toMap() {
var map = <String, dynamic>{colName: name, colMobile: mobile};
if (id != null) map[colId] = id;
return map;
}
Customer.fromMap(Map<String, dynamic> map) {
id = map[colId];
name = map[colName];
mobile = map[colMobile];
}
#override
bool operator ==(Object other) =>
identical(this, other) ||
other is Customer &&
runtimeType == other.runtimeType &&
name == other.name;
#override
int get hashCode => name.hashCode;
#override
String toString() {
return name;
}
}
Here is my database:
import 'dart:async';
import 'dart:io';
import 'package:path_provider/path_provider.dart';
import 'package:sqflite/sqflite.dart';
import 'package:path/path.dart';
import 'customer.dart';
class DatabaseHelper {
static const _databaseVersion = 1;
static const _databaseName = 'Kiloin.db';
DatabaseHelper._();
static final DatabaseHelper instance = DatabaseHelper._();
Database _database;
Future<Database> get database async {
if (_database != null) return _database;
_database = await _initDatabase();
return _database;
}
_initDatabase() async {
Directory dataDirectory = await getApplicationDocumentsDirectory();
String dbPath = join(dataDirectory.path, _databaseName);
return await openDatabase(
dbPath,
version: _databaseVersion,
onCreate: _onCreateDB,
);
}
_onCreateDB(Database db, int version) async {
await db.execute('''
CREATE TABLE ${Customer.tblCustomer}(
${Customer.colId} INTEGER PRIMARY KEY AUTOINCREMENT,
${Customer.colName} TEXT NOT NULL,
${Customer.colMobile} TEXT NOT NULL
)
''');
}
Future<int> insertBikeContact(Customer customer) async {
Database db = await database;
return await db.insert(Customer.tblCustomer, customer.toMap());
}
Future<List<Customer>> getCustomer() async {
Database db = await database;
List<Map> contact = await db.query(Customer.tblCustomer);
return contact.length == 0
? []
: contact.map((e) => Customer.fromMap(e)).toList();
}
Future<int> updateCustomer(Customer customer) async {
Database db = await database;
return await db.update(Customer.tblCustomer, customer.toMap(),
where: '${Customer.colId}=?', whereArgs: [customer.id]);
}
Future<int> deleteContact(int id) async {
Database db = await database;
return await db.delete(Customer.tblCustomer,
where: '${Customer.colId}=?', whereArgs: [id]);
}
}
The value that you get from onSuggestionSelected is the customer. Use that value to update _mobileController.text.
onSuggestionSelected: (customer) {
if (customer != null) {
setState(() {
_mobileController.text = customer.mobile;
});
}
}