This question already has an answer here:
Flutter Error: The Method toDouble() was called on null, Tried calling toDouble
(1 answer)
Closed 1 year ago.
I am stuck on the error saying toDouble was called on null. I have checked my code many times and I can't figure out whats happening.
This is the code for bottom_sheet_panel
import 'package:flutter/material.dart';
import 'package:freezeria/Screens/services/database.dart';
import 'package:freezeria/common_code/common.dart';
import 'package:freezeria/common_code/loader.dart';
import 'package:freezeria/req_info/shakes.dart';
import 'package:freezeria/req_info/user.dart';
import 'package:provider/provider.dart';
class bottomSheetPanel extends StatefulWidget {
#override
_bottomSheetPanelState createState() => _bottomSheetPanelState();
}
class _bottomSheetPanelState extends State<bottomSheetPanel> {
final _formkey = GlobalKey<FormState>();
final List<String> blending = ['1', '2', '3', '4', '5'];
final List<String> cupsize = ['Select', 'Small', 'Medium', 'Large'];
final List<String> flavour = [
'Chocolate',
'Vanilla',
'Strawberry',
'Blueberry',
'Raspberry',
'Kiwi',
'Select'
];
final List<String> cream = [
'Whipped',
'Caramel',
'Chocolate',
'Strawberry',
'Select'
];
final List<String> toppings = [
'Oreo',
'Cherry',
'Strawberry',
'Sweet Lime',
'Waffle',
'Blackberries',
'Select'
];
String _currentName;
String _currentCupSize;
int _currentBlend;
String _currentFlavour;
String _currentCream;
String _currentToppings;
#override
Widget build(BuildContext context) {
final receiveUser = Provider.of<User>(context);
return StreamBuilder<UserData>(
stream: Database(uid: receiveUser.uid).userDataStream,
builder: (context, snapshot) {
if (snapshot.hasData) {
UserData recentData = snapshot.data;
return Form(
key: _formkey,
child: SingleChildScrollView(
child: Column(
children: [
Text(
"Update Your Data",
style: TextStyle(fontSize: 20.0),
),
SizedBox(
height: 20.0,
),
TextFormField(
initialValue: recentData.Name,
decoration:
decorationCode.copyWith(hintText: 'Enter your name'),
validator: (val) =>
val.isEmpty ? 'Please enter a name' : null,
onChanged: (val) => setState(() {
return _currentName = val;
}),
),
SizedBox(
height: 20.0,
),
DropdownButtonFormField(
value: _currentCupSize ?? recentData.CupSize,
items: cupsize.map((size) {
return DropdownMenuItem(
value: size,
child: Text('$size Size'),
);
}).toList(),
onChanged: (val) => setState(() {
return _currentCupSize = val;
}),
),
SizedBox(
height: 20.0,
),
Slider(
value: (_currentBlend ?? recentData.Blend).toDouble(),
activeColor:
Colors.grey[_currentBlend ?? recentData.Blend],
inactiveColor:
Colors.grey[_currentBlend ?? recentData.Blend],
min: 100.0,
max: 700.0,
divisions: 6,
onChangeEnd: (val) => setState(() {
return _currentBlend = val.round();
}),
),
SizedBox(
height: 20.0,
),
DropdownButtonFormField(
value: _currentFlavour ?? recentData.Flavour,
items: flavour.map((flav) {
return DropdownMenuItem(
value: flav,
child: Text('$flav Flavour'),
);
}).toList(),
onChanged: (val) => setState(() {
return _currentFlavour = val;
}),
),
SizedBox(
height: 20.0,
),
DropdownButtonFormField(
value: _currentCream ?? recentData.Cream,
items: cream.map((crem) {
return DropdownMenuItem(
value: crem,
child: Text('$crem Cream'),
);
}).toList(),
onChanged: (val) => setState(() {
return _currentCream = val;
}),
),
SizedBox(
height: 20.0,
),
DropdownButtonFormField(
value: _currentToppings ?? recentData.Toppings,
items: toppings.map((top) {
return DropdownMenuItem(
value: top,
child: Text('$top Toppings'),
);
}).toList(),
onChanged: (val) => setState(() {
return _currentToppings = val;
}),
),
SizedBox(
height: 20.0,
),
ElevatedButton(
onPressed: () async {
print(_currentName);
print(_currentBlend);
print(_currentCupSize);
print(_currentFlavour);
print(_currentToppings);
},
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all<Color>(
Colors.purple[300]),
foregroundColor:
MaterialStateProperty.all<Color>(Colors.white),
),
child: Text(
'UPDATE',
style: TextStyle(color: Colors.white),
),
)
],
),
),
);
} else {
Loading();
}
});
}
}
The toDouble() in Slider Function is giving error, also recentData.name is not updating the name in the bottom sheet.
It is seen that _currentBlend and recentData are giving null values, how do I correct it?
Any help will be much appreciated:)
The problem is in this line value: (_currentBlend ?? recentData.Blend).toDouble(),
and the error is saying that you called the toDouble() function on a null object (_currentBlend ?? recentData.Blend) this portion of code giving null so you can not cal toDouble() on it.
Solution: first of all you should make sure that (_currentBlend ?? recentData.Blend) this code must not be null. or you can handle it by using null safety.
try: replace
value: (_currentBlend ?? recentData.Blend).toDouble(), this line with
value: (_currentBlend ?? recentData.Blend)?.toDouble(),
Related
this is the formField that is uploading no value i tried using a controller but seems now event compatible.the rest of the textformfields are working but i dont know why the formField is uploading a empty value to the firebase
Container(
margin: const EdgeInsets.only(left: 15, top: 10, right: 15),
child: FormField<String>(
builder: (FormFieldState<String> state) {
return InputDecorator(
decoration: InputDecoration(
contentPadding:
const EdgeInsets.fromLTRB(12, 10, 20, 20),
labelText: "EVENT TYPE/CATEGORY",
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10.0),
),
),
isEmpty: eventcategoryChoosen == null ||
eventcategoryChoosen == '',
child: DropdownButtonHideUnderline(
child: DropdownButtonFormField<EventCatListDataModel>(
validator: (_eventcategoryChoosen) {
if (_eventcategoryChoosen == null) {
return ("section cannot be Empty");
}
print(_eventcategoryChoosen);
return null;
},
onSaved: (_eventcategoryChoosen) {
setState(() {
eventcategoryEditingController.text =
_eventcategoryChoosen! as String;
});
print(_eventcategoryChoosen);
},
style: const TextStyle(
fontSize: 16,
color: blue,
),
hint: const Text(
"Select Event",
style: TextStyle(
color: green,
fontSize: 16,
),
),
isExpanded: true,
value: eventcategoryChoosen,
isDense: true,
onChanged: (newSelectedBank) async {
_onDropDownItemSelected(newSelectedBank!);
setState(() {
eventcategoryChoosen = newSelectedBank;
state.didChange(newSelectedBank.toString());
});
print(eventcategoryChoosen.toString());
},
items: eventcategoryList
.map<DropdownMenuItem<EventCatListDataModel>>(
(EventCatListDataModel category) {
return DropdownMenuItem(
value: category,
child: Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
CircleAvatar(
child: Image.asset(category.eventlogo),
),
// Icon(valueItem.eventlogo),
const SizedBox(
width: 15,
),
Text(
category.eventname,
style: const TextStyle(color: cyanwe),
),
],
),
);
}).toList(),
),
),
);
},
),
),
this is the how the events model ,how we upload to firebase.but after each upload the 'eventcatecogty' field is empty.
import 'package:cloud_firestore/cloud_firestore.dart';
class EventsModel {
late String eventName;
late String date;
late String gateopens;
late int ticketPrice;
late String quantityofticket;
late String descriptionevent;
late String locationevent;
late String eventcategoryChoosen;
late List<String> imagesUrl;
EventsModel(
{required this.eventName,
required this.date,
required this.gateopens,
required this.ticketPrice,
required this.quantityofticket,
required this.descriptionevent,
required this.locationevent,
required this.imagesUrl,
required this.eventcategoryChoosen});
CollectionReference db = FirebaseFirestore.instance.collection('events');
Future<void> addEvent(EventsModel eventModel) async {
Map<String, dynamic> data = {
"eventName": eventModel.eventName,
"date": eventModel.date,
"gateopens": eventModel.gateopens,
"ticketPrice": eventModel.ticketPrice,
"quantityofticket": eventModel.quantityofticket,
"descriptionevent": eventModel.descriptionevent,
"locationevent": eventModel.locationevent,
"imagesUrl": eventModel.imagesUrl,
"eventcategory": eventModel.eventcategoryChoosen,
};
await db.add(data);
}
}
this is the class model feeding the dropdown. im trying to figure out why my code is not uploading event caterory.help!!
class EventCatListDataModel {
String eventname;
String eventlogo;
EventCatListDataModel({required this.eventname, required this.eventlogo});
}
List<EventCatListDataModel> eventcategoryList = [
EventCatListDataModel(eventlogo: "assets/icons/club.png", eventname: 'Club'),
EventCatListDataModel(
eventlogo: "assets/icons/concert.png", eventname: "Concerts"),
EventCatListDataModel(
eventlogo: "assets/icons/road-trip.png", eventname: "road-trip"),
EventCatListDataModel(
eventlogo: "assets/icons/camping.png", eventname: 'camping'),
EventCatListDataModel(
eventlogo: "assets/images/category/salad.png",
eventname: "sunday branch"),
EventCatListDataModel(
eventlogo: "assets/icons/motorbike.png", eventname: "Motobike meet"),
EventCatListDataModel(
eventlogo: "assets/icons/car.png", eventname: "Car meet"),
];
I am trying to fetch data from my create and showing those data into my update page data are coming. I am able to update from normal textformfield, but am not able to edit data from my drop down table. Please anyone give suggestion that where am doing mistake.
class UpdateEdic extends StatefulWidget {
final String docId;
const UpdateEdic({
Key? key,
required this.docId,
}) : super(key: key);
#override
_UpdateEdicState createState() => _UpdateEdicState();
}
class _UpdateEdicState extends State<UpdateEdic> {
final _formKey = GlobalKey<FormState>();
CollectionReference devtradecalls =
FirebaseFirestore.instance.collection('dev-trade-calls');
List<String> tslList = ['T', 'F'];
String imageUrl = "";
List<String> archivedList = ['T', 'F'];
List<String> targetAchivedList = ['T', 'F'];
DateTime tgtachtime = DateTime.now();
DateTime calltime = DateTime.now();
List tools = [];
List indicators = [];
String imageFilePath = "";
File? _imageFile;
final _picker = ImagePicker();
final format = DateFormat("HH:mm dd-MM-yyyy");
Future<void> updateEdicData(id, tsl, pattern, indicators, tools, img, notes,
targetAchieved, targetAchievedTime, archived, callTime) {
return devtradecalls
.doc(id)
.update({
'tsl': tsl,
'tslList': tslList,
'pattern': pattern,
'indicators': indicators,
'tools': tools,
'img': img,
'notes': notes,
'targetAchieved': targetAchieved,
'targetAchievedTime': targetAchievedTime,
'archived': archived,
'callTime': callTime
})
.then((value) => Navigator.pop(context))
.catchError((error) => print('Failed to update: $error'));
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Update Edic'),
),
body: Form(
key: _formKey,
child: FutureBuilder<DocumentSnapshot<Map<String, dynamic>>>(
future: FirebaseFirestore.instance
.collection('dev-trade-calls')
.doc(widget.docId)
.get(),
builder: (_, snapshot) {
if (snapshot.hasData) {
var data = snapshot.data!.data();
var tsl = data!['tsl'];
var pattern = data['pattern'];
List indicators = data['indicators'];
List tools = data['tools'];
var imgUrl = data['img'];
var notes = data['notes'];
var targetAchieved = data['targetAchieved'];
DateTime? targetAchievedTime =
(data['targetAchievedTime'] as Timestamp).toDate();
var archived = data['archived'];
DateTime? callTime = (data['callTime'] as Timestamp).toDate();
return Padding(
padding: const EdgeInsets.all(16.0),
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Trailing Stop Loss',
style: labelStyle.copyWith(color: primaryColor)),
DropdownButton<String>(
isExpanded: true,
value: tsl,
items: tslList.map((String items) {
return DropdownMenuItem(
value: items,
child: Text(kEdictsl[items]!),
);
}).toList(),
onChanged: (String? newValue) {
setState(() {
tsl = newValue;
});
},
),
SizedBox(
height: 24,
),
Text('Pattern',
style: labelStyle.copyWith(color: primaryColor)),
TextFormField(
autocorrect: true,
enableSuggestions: true,
initialValue: pattern,
onChanged: (value) {
pattern = value;
},
keyboardType: TextInputType.multiline,
),
SizedBox(
height: 24,
),
Text('Indicators',
style: labelStyle.copyWith(color: primaryColor)),
MultiSelectDialogField(
listType: MultiSelectListType.CHIP,
searchable: true,
initialValue: indicators,
items: kEdicIndicators
.map((t) => MultiSelectItem<dynamic>(t, t))
.toList(),
buttonIcon: Icon(
Icons.candlestick_chart,
color: Colors.blue,
),
onConfirm: (value) => indicators = value,
chipDisplay: MultiSelectChipDisplay(
onTap: (value) {
indicators.remove(value);
},
),
),
SizedBox(height: 24.0),
Text('Tools',
style: labelStyle.copyWith(color: primaryColor)),
MultiSelectDialogField(
listType: MultiSelectListType.CHIP,
searchable: true,
items: kEdicTools
.map((t) => MultiSelectItem<dynamic>(t, t))
.toList(),
initialValue: tools,
buttonIcon: Icon(
Icons.settings_sharp,
color: Colors.blue,
),
onConfirm: (results) {
tools = results;
},
chipDisplay: MultiSelectChipDisplay(
onTap: (value) {
tools.remove(value);
},
),
),
SizedBox(
height: 24,
),
Text('Notes',
style: labelStyle.copyWith(color: primaryColor)),
TextFormField(
initialValue: notes,
autocorrect: true,
onChanged: (value) {
notes = value;
},
enableSuggestions: true,
keyboardType: TextInputType.multiline,
minLines: 1,
maxLines: 3,
),
SizedBox(
height: 24,
),
Text('Target Achived',
style: labelStyle.copyWith(color: primaryColor)),
DropdownButton<String>(
isExpanded: true,
value: targetAchieved,
hint: const Text('True/False'),
items: targetAchivedList.map((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(kEdicTargetAchived[value]!),
);
}).toList(),
onChanged: (value) => targetAchieved = value,
// {
// setState(() {
// // targetAchived = value!;
// });
// },
),
const SizedBox(height: 24.0),
Text('Target Achieved Time',
style: labelStyle.copyWith(color: primaryColor)),
SizedBox(
height: 24,
),
DateTimeField(
format: format,
onShowPicker: (context, currentValue) async {
final date = await showDatePicker(
context: context,
firstDate: DateTime(1900),
initialDate: currentValue ?? DateTime.now(),
lastDate: DateTime(2100));
if (date != null) {
final time = await showTimePicker(
context: context,
initialTime: TimeOfDay.fromDateTime(
currentValue ?? DateTime.now()),
);
return DateTimeField.combine(date, time);
} else {
return currentValue;
}
},
validator: (date) =>
date == null ? 'Invalid date' : null,
initialValue: targetAchievedTime,
onChanged: (value) => targetAchievedTime = value,
onSaved: (date) => setState(() {
// savedCount++;
}),
),
const SizedBox(
height: 24,
),
Text('Archived',
style: labelStyle.copyWith(color: primaryColor)),
DropdownButton<String>(
isExpanded: true,
value: archived,
hint: const Text('True/False'),
items: archivedList.map((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(kEdicArchived[value]!),
);
}).toList(),
onChanged: (value) => archived = value,
),
SizedBox(
height: 24,
),
Text('Call Time',
style: labelStyle.copyWith(color: primaryColor)),
SizedBox(
height: 24,
),
DateTimeField(
format: format,
onShowPicker: (context, currentValue) async {
final date = await showDatePicker(
context: context,
firstDate: DateTime(1900),
initialDate: currentValue ?? DateTime.now(),
lastDate: DateTime(2100));
if (date != null) {
final time = await showTimePicker(
context: context,
initialTime: TimeOfDay.fromDateTime(
currentValue ?? DateTime.now()),
);
return DateTimeField.combine(date, time);
} else {
return currentValue;
}
},
validator: (date) =>
date == null ? 'Invalid date' : null,
initialValue: callTime,
onChanged: (value) => callTime = value,
),
const SizedBox(
height: 24,
),
Text('Image URL',
style: labelStyle.copyWith(color: primaryColor)),
TextFormField(
autocorrect: true,
enableSuggestions: true,
initialValue: imgUrl,
onChanged: (value) {
imgUrl = value;
},
keyboardType: TextInputType.multiline,
minLines: 1,
maxLines: 3,
),
Text('Add Image',
style: labelStyle.copyWith(color: primaryColor)),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
ElevatedButton.icon(
onPressed: () async {
await pickImageFromCamera();
},
icon: Icon(
Icons.add_a_photo,
),
label: const Text('Camera'),
),
ElevatedButton.icon(
onPressed: () async {
await pickImageFromGallery();
},
icon: Icon(
Icons.collections,
),
label: const Text('Gallery'),
),
],
),
_previewImage(),
SizedBox(height: 24.0),
ElevatedButton(
style: ElevatedButton.styleFrom(
minimumSize: Size(
double.infinity,
48,
), // double.infinity is the width and 30 is the height
),
onPressed: () {
if (_formKey.currentState!.validate()) {
updateEdicData(
widget.docId,
tsl,
pattern,
indicators,
tools,
imgUrl,
notes,
targetAchieved,
targetAchievedTime,
archived,
callTime);
Navigator.pop(context);
}
},
child: Text('Update'),
)
],
),
),
);
}
if (snapshot.hasError) {
return const Text('"Something Went Wrong"');
}
return const Center(
child: CircularProgressIndicator(),
);
},
)),
);
}
}
This is the Realtime Firebase data
In this pic, you can see data and only I want to show available items documents from the database. But it shows all the documents.
I just want to show only available data. If you know how to do it to get once or using stream or any other solution so please help because I was stuck in it for 3 days.
Here is the body of the main page working
class OrderMenu extends StatefulWidget {
const OrderMenu({
Key? key,
required this.dbChild,
}) : super(key: key);
final String dbChild;
#override
_OrderMenuState createState() => _OrderMenuState();
}
class _OrderMenuState extends State<OrderMenu> {
DatabaseReference db = FirebaseDatabase.instance.reference();
User? curUser = FirebaseAuth.instance.currentUser;
int? len;
List<GetData>? data;
Map<String, dynamic>? proceed;
List<GetData>? AvailData;
late List<bool>? avail = List.generate(
len!,
(index) => false,
);
#override
Widget build(BuildContext context) {
return StreamBuilder<List<GetData>>(
stream: DataStreamPublisher(widget.dbChild).getMenuStream(),
builder: (context, snapshot) {
if (snapshot.hasData) {
data = snapshot.data;
len = data!.length;
return SafeArea(
child: SingleChildScrollView(
child: Container(
margin: EdgeInsets.symmetric(vertical: 10.0),
width: double.infinity,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
width: double.infinity,
child: DataTable2(
showBottomBorder: true,
headingRowHeight: 40,
showCheckboxColumn: true,
sortAscending: true,
columnSpacing: 5,
dataRowHeight: 60,
dividerThickness: 2,
bottomMargin: 20.0,
checkboxHorizontalMargin: 5,
columns: [
DataColumn2(
size: ColumnSize.L,
label: Center(
child: Text(
"Item Name",
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
),
),
DataColumn2(
size: ColumnSize.S,
label: Center(
child: Text(
"Price",
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
),
),
DataColumn2(
size: ColumnSize.L,
label: Center(
child: Text(
"Quantity",
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
),
),
],
rows: List<DataRow>.generate(
data!.length,
(index) => DataRow2(
selected: avail![index],
onSelectChanged: (bool? value) {
setState(() {
avail![index] = value!;
});
},
color: MaterialStateProperty.resolveWith<Color?>(
(Set<MaterialState> states) {
if (states.contains(MaterialState.selected)) {
return Theme.of(context)
.colorScheme
.primary
.withOpacity(0.08);
}
return null;
},
),
cells: [
DataCell(
Text(
data![index].Juice_Name,
),
),
DataCell(
Center(
child: Text(
data![index].Price,
),
),
),
DataCell(
IncDecButton(),
),
],
),
),
),
),
],
),
),
),
);
} else if (snapshot.hasError) {
return Center(
child: Text(
'Add Item in Menu.',
style: TextStyle(
fontSize: 18,
),
),
);
}
return Center(
child: const CircularProgressIndicator(),
);
},
);
}
}
**This is stream of GetDataPublisher**
class DataStreamPublisher {
final String dbChild;
DatabaseReference database = FirebaseDatabase.instance.reference();
User? curUser = FirebaseAuth.instance.currentUser;
DataStreamPublisher(this.dbChild);
Stream<List<GetData>> getDataStream() {
final dataStream = database.child(curUser!.uid).child(dbChild).onValue;
final streamToPublish = dataStream.map((event) {
final dataMap = Map<String, dynamic>.from(event.snapshot.value);
final dataList = dataMap.entries.map((e) {
return GetData.fromRTDB(Map<String, dynamic>.from(e.value));
}).toList();
return dataList;
});
return streamToPublish;
}
Stream<List<GetData>> getMenuStream() {
final dataStream = database.child(curUser!.uid).child(dbChild).onValue;
final streamToPublish = dataStream.map((event) {
final dataMap = Map<String, dynamic>.from(event.snapshot.value);
final dataList = dataMap.entries.map((e) {
**if (e.value["Available"] == true) {
print("Here I need a condition to get available data. OR any other possibility");
}**
return GetData.fromRTDB(Map<String, dynamic>.from(e.value));
}).toList();
return dataList;
});
return streamToPublish;
}
}
This is GetData class
class GetData {
String Juice_Name;
String Price;
bool Available;
var key;
GetData({
required this.Juice_Name,
required this.Available,
required this.Price,
required this.key,
});
factory GetData.fromRTDB(Map<String, dynamic> data) {
return GetData(
Juice_Name: data['Juice_Name'] ?? 'Enter Juice Name',
Price: data['Price'] ?? 'Enter Price',
Available: data['Available'] ?? false,
key: data['Key'] ?? 'key',
);
}
}
When you are using the following reference:
final dataStream = database.child(curUser!.uid).child(dbChild)
You will indeed get all the data under the "dbChild" node.
If you only need to get the objects that have the "Available" property set to true, then you should use a Query that look like this:
DatabaseReference db = FirebaseDatabase.instance.reference();
var query = db.child(curUser!.uid).child('Juices').orderByChild("Available").equalTo(true);
When I run my program I get an error that says this:
Error: Could not find the correct Provider<EventsServices> above this FormPage Widget
And it says this was in the stack:
When the exception was thrown, this was the stack:
#0 Provider._inheritedElementOf (package:provider/src/provider.dart:332:7)
#1 Provider.of (package:provider/src/provider.dart:284:30)
#2 ReadContext.read (package:provider/src/provider.dart:610:21)
#3 _FormPageState.build.<anonymous closure> (package:localeventsapp/ui/homepage/form_widget.dart:204:29)
#4 _InkResponseState._handleTap (package:flutter/src/material/ink_well.dart:991:20)
...
Handler: "onTap"
Recognizer: TapGestureRecognizer#edec2
debugOwner: GestureDetector
state: possible
won arena
finalPosition: Offset(203.4, 442.0)
finalLocalPosition: Offset(59.2, 21.6)
button: 1
sent tap down
====================================================================================================
The error points to this dart file I'm using as a form to collect some information that I want to append to Firebase Firestore but it won't store the data there because of this error I'm assuming.
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:date_time_picker/date_time_picker.dart';
import 'package:localeventsapp/events_services.dart';
import 'package:localeventsapp/model/Firebase_eventID.dart';
import 'package:provider/provider.dart';
CollectionReference userEvents = FirebaseFirestore.instance.collection("Events");
FirebaseAuth auth = FirebaseAuth.instance;
String uid = auth.currentUser.uid.toString();
class FormPage extends StatefulWidget {
#override
_FormPageState createState() => _FormPageState();
}
class _FormPageState extends State<FormPage> {
final TextEditingController eventNameController = TextEditingController();
final TextEditingController locationController = TextEditingController();
final TextEditingController descriptionController = TextEditingController();
final TextEditingController creatorController = TextEditingController();
String categoryID;
int dateTime;
// final TextEditingController dateController = TextEditingController();
final GlobalKey<_FormPageState> _formKey = GlobalKey<_FormPageState>();
Widget _buildName() {
return TextFormField(
controller: eventNameController,
decoration: InputDecoration(
labelText: 'Event Name',
border:
OutlineInputBorder(borderRadius: BorderRadius.circular(15.0))),
validator: (String value) {
if (value.isEmpty) {
return 'Name is required';
}
return null;
},
);
}
Widget _buildLocation() {
return TextFormField(
controller: locationController,
decoration: InputDecoration(
labelText: 'Location',
border:
OutlineInputBorder(borderRadius: BorderRadius.circular(15.0))),
validator: (String value) {
if (value.isEmpty) {
return 'Location is required';
}
return null;
},
);
}
Widget _buildDescription() {
return TextFormField(
controller: descriptionController,
decoration: InputDecoration(
labelText: 'Description',
border:
OutlineInputBorder(borderRadius: BorderRadius.circular(15.0))),
validator: (String value) {
if (value.isEmpty) {
return 'Description is required';
}
return null;
},
);
}
Widget _buildCategory() {
return DropdownButtonFormField<String>(
items: [
DropdownMenuItem<String>(
child: Text('Music'),
value: '1',
),
DropdownMenuItem<String>(
child: Text('Meet up'),
value: '2',
),
DropdownMenuItem<String>(
child: Text('Golf'),
value: '3',
),
DropdownMenuItem<String>(
child: Text('Birthday'),
value: '4',
),
DropdownMenuItem<String>(
child: Text('Cook Out'),
value: '5',
),
],
onChanged: (String value) {
setState(() {
categoryID = value;
});
},
value: categoryID,
hint: Text('Category'),
);
}
Widget _buildDate() {
DateTime currentDate = DateTime.now();
DateTimePicker(
type: DateTimePickerType.dateTimeSeparate,
dateMask: 'd MMM, yyyy',
initialValue: DateTime.now().toString(),
firstDate: DateTime(2000),
lastDate: DateTime(2100),
icon: Icon(Icons.event),
dateLabelText: 'Date',
timeLabelText: "Time",
onChanged:
(val) => print(val),
validator: (val) {
print(val);
return null;
},
onSaved: (val) => print(val),
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Create Event'), backgroundColor: Color(0xFF6F35A5)),
body: Container(
margin: EdgeInsets.all(24),
child: Form(
key: _formKey,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
_buildName(),
SizedBox(height: 10),
_buildLocation(),
SizedBox(height: 10),
_buildDescription(),
SizedBox(height: 10),
Row(
children: [
Align(
alignment: Alignment.bottomLeft,
child: Container(width:100, child: _buildCategory()),
),
Spacer(),
Align(
alignment: Alignment.bottomRight ,
child: Container(width: 200, child: _buildDate()),
),
],
),
//_buildGuests(),
SizedBox(height: 1),
ElevatedButton(
child: Text('Create Event',
style: TextStyle(
color: Colors.black,
fontSize: 16,
)),
onPressed: () {
context.read<EventsServices>().addEvent(
eventName: eventNameController.text.trim(),
location: locationController.text.trim(),
description: descriptionController.text.trim(),
category: categoryID.trim(),
// dateTime: dateTime,
creatorUID: uid,
);
}),
],
),
),
),
);
}
}
I'm relatively new to Flutter so I'm not sure what I need to do. Any ideas?
I found out what was wrong.
I hadn't included a provider in the main dart file. Now it works.
This is where I write the data to my Firebase,
class userContent {
final String uid;
userContent({this.uid});
bool isLoggedIn() {
if (FirebaseAuth.instance.currentUser() != null) {
return true;
} else {
return false;
}
}
Future<Void> addData(propertyData) async {
if (isLoggedIn()) {
Firestore.instance
.collection('userContent')
.document('posts')
.collection('postCollection')
.add(propertyData)
.catchError((e) {
print(e);
});
} else {
print('You need to be logged in');
}
}
getData() async {
return await Firestore.instance
.collection('userContent')
.document('posts')
.collection('postCollection')
.snapshots();
}
updateData(selectedDoc, newValues) {
Firestore.instance
.collection('userContent')
.document('posts')
.collection('postCollection')
.document(selectedDoc)
.updateData(newValues)
.catchError((e) {
print(e);
});
}
deleteData(docId) {
Firestore.instance
.collection('userContent')
.document('posts')
.collection('postCollection')
.document(docId)
.delete()
.catchError((e) {
print(e);
});
}
UserContent _userDataFromSnapshot(QuerySnapshot snapshot) {
return UserContent(
uid: uid,
);
}
Stream<UserContent> get userDataStream {
return Firestore.instance
.collection('userContent')
.document('posts')
.collection(uid)
.snapshots()
.map(_userDataFromSnapshot);
}
}
this is what I use to show the dialog where users can add a new property to my Firebase storage,
Future<bool> addDialog(BuildContext context) async {
final user = Provider.of<User>(context);
return showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return AlertDialog(
title: Text('Add Data', style: TextStyle(fontSize: 15.0)),
content: SingleChildScrollView(
child: Form(
key: _formKey,
child: Column(
children: <Widget>[
TextFormField(
validator: (val) =>
val.isEmpty ? 'Enter the property\'s title' : null,
decoration:
InputDecoration(hintText: 'Enter property title'),
onChanged: (value) {
this.propertyTitle = value;
},
),
SizedBox(height: 5.0),
TextFormField(
validator: (val) =>
val.isEmpty ? 'Enter the property\'s address' : null,
decoration: InputDecoration(
hintText: 'Enter the property\'s Address'),
onChanged: (value) {
this.propetyAddress = value;
},
),
SizedBox(height: 5.0),
TextFormField(
validator: (val) =>
val.isEmpty ? 'Enter the property\'s postcode' : null,
decoration: InputDecoration(
hintText: 'Enter the property\'s potcode'),
onChanged: (value) {
this.propertyPostcode = value;
},
),
SizedBox(height: 5.0),
TextFormField(
validator: (val) =>
val.isEmpty ? 'Enter the property\'s price' : null,
decoration: InputDecoration(hintText: 'Enter a price'),
onChanged: (value) {
this.propertyPrice = value;
},
),
SizedBox(height: 5.0),
TextFormField(
validator: (val) => val.isEmpty
? 'Enter sales type \'(For Sale or To rent)\''
: null,
decoration:
InputDecoration(hintText: 'Enter selling type'),
onChanged: (value) {
this.sellingType = value;
},
),
SizedBox(height: 5.0),
TextFormField(
validator: (val) =>
val.isEmpty ? 'Enter a description' : null,
decoration:
InputDecoration(hintText: 'Enter Detail Description'),
onChanged: (value) {
this.moreDetails = value;
},
),
DropdownButtonFormField(
value: numberOfbaths ?? '1',
items: bathrooms.map((bathrooms) {
return DropdownMenuItem(
value: bathrooms,
child: Text('$bathrooms bathrooms'),
);
}).toList(),
onChanged: (String value) {
this.numberOfbaths = value;
},
),
DropdownButtonFormField(
value: numberOfbedrooms ?? '1',
items: bedrooms.map((bedrooms) {
return DropdownMenuItem(
value: bedrooms,
child: Text('$bedrooms bedrooms'),
);
}).toList(),
onChanged: (String value) {
this.numberOfbedrooms = value;
},
),
DropdownButtonFormField(
value: numberOflivingrooms ?? '1',
items: livingrooms.map((livingrooms) {
return DropdownMenuItem(
value: livingrooms,
child: Text('$livingrooms livingrooms'),
);
}).toList(),
onChanged: (String value) {
this.numberOflivingrooms = value;
},
),
TextFormField(
validator: (val) =>
val.isEmpty ? 'Enter energy costs per month' : null,
decoration:
InputDecoration(hintText: 'Energy Costs per month'),
onChanged: (value) {
this.energyPermonth = value;
},
),
TextFormField(
validator: (val) =>
val.isEmpty ? 'Enter tax costs per month' : null,
decoration:
InputDecoration(hintText: 'Tax Costs per month'),
onChanged: (value) {
this.taxPermonth = value;
},
),
TextFormField(
validator: (val) =>
val.isEmpty ? 'Enter water costs per month' : null,
decoration:
InputDecoration(hintText: 'Water Costs per month'),
onChanged: (value) {
this.waterPermonth = value;
},
),
],
),
),
),
actions: <Widget>[
FlatButton(
child: Text('Add'),
textColor: Colors.blue,
onPressed: () {
if (_formKey.currentState.validate()) {
Navigator.of(context).pop();
userContent(uid: user.uid).addData({
'uid': user.uid,
'Property Title': this.propertyTitle,
'Seller Name': this.sellerName,
'Property Address': this.propetyAddress,
'Property Postcode': this.propertyPostcode,
'Property Price': this.propertyPrice,
'Selling Type': this.sellingType,
'more Details': this.moreDetails,
'Number of Bathrooms': this.numberOfbaths,
'Number of Bedrooms': this.numberOfbedrooms,
'Number of Livingrooms': this.numberOflivingrooms,
'Energy per Month': this.energyPermonth,
'Tax per Month': this.taxPermonth,
'Water per Month': this.waterPermonth,
}).catchError((e) {
print(e);
print(user.uid);
});
}
},
)
],
);
});
}
I have figured out how to include the uid but I don't know how to use it for deleting a document.
I have seen lots of different suggestions on stack flow but I struggle in my case.
Please, could someone help me and others who would run into the same kind of issue then you!
This should work. Don't forget to make it an sync
await Firestore.instance
.collection('userContent') .
document('posts') .
collection('postCollection') .
document(uid) .delete()