Flutter Firestore sets data before page is loaded - flutter

I am trying to add my data in a textformfield which then saves to firestore, this includes the documentID. The data comes back as null or "" for some reason.
Below is my code:
final barcode = TextEditingController();
final price = TextEditingController();
final stock = TextEditingController();
final color = TextEditingController();
addData() {
Map<String, dynamic> theData = {
"Color" : color.text,
"Price" : price.text,
"Stock" : stock.text,
};
CollectionReference collectionReference = Firestore.instance.collection("products");
FirebaseFirestore.instance.collection("products").doc(barcode.text).set(theData);
collectionReference.add(theData);
}
I have tried making it async but still nothing, I want the data to be set when I click the done button which has a onpressed method calling the addData.
This is my data in firestore when I only set the data and not the ID:

You have to use await
addData() async { // ASYNC HERE
Map<String, dynamic> theData = {
"Color" : color.text,
"Price" : price.text,
"Stock" : stock.text,
};
CollectionReference collectionReference = Firestore.instance.collection("products");
await collectionReference.doc(barcode.text).set(theData, merge:true); // AWAIT HERE
or
CollectionReference collectionReference = Firestore.instance.collection("products");
await collectionReference.doc(barcode.text).updateData(theData); // AWAIT HERE
}
Also not sure why you both set and add theData? Use updateData() or set() with merge:true. The document will be created either way

Related

Type 'Future<QuerySnapshot<Map<String, dynamic>>>' is not a subtype of type 'DocumentSnapshot<Object?>' in type cast

static CollectionReference doses =
FirebaseFirestore.instance.collection('Doses');
void setDoseDetails(
TextEditingController endController,
TextEditingController startController,
TextEditingController doseController,
int noPills,
int doseRep) {
var dose =
doses.where('userID', isEqualTo: Auth().uID).get() as DocumentSnapshot;
Map<String, dynamic> userData = dose as Map<String, dynamic>;
endController.text = userData['endDate'];
startController.text = userData['startDate'];
noPills = userData['noPills'];
doseController.text = userData['doseVal'];
doseRep = userData["doseRep"];
}
I'm trying to retrieve data from Firebase using this code and it's not working.
If you see the return type of the get() method that you are trying to call in doses.where('userID', isEqualTo: Auth().uID).get() it is Future<QuerySnapshot<T>>. There are two problems in your approach:
You are not awaiting the result of doses.where('userID', isEqualTo: Auth().uID).get().
You are forcefully type-casting a QuerySnapshot into a DocumentSnapshot. If doses.where('userID', isEqualTo: Auth().uID).get() after awaiting, returns a QuerySnapshot, the variable holding that value should also be of the type QuerySnapshot.
Here is what you can do instead:
static CollectionReference doses =
FirebaseFirestore.instance.collection('Doses');
Future<void> setDoseDetails(
TextEditingController endController,
TextEditingController startController,
TextEditingController doseController,
int noPills,
int doseRep) async {
QuerySnapshot dose =
await doses.where('userID', isEqualTo: Auth().uID).get();
Map<String, dynamic> userData = dose as Map<String, dynamic>;
endController.text = userData['endDate'];
startController.text = userData['startDate'];
noPills = userData['noPills'];
doseController.text = userData['doseVal'];
doseRep = userData["doseRep"];
}
If you notice in the solution above,
I have changed the return type of setDoseDetails because it can't be just void and has to be Future<void> because you are dealing with futures.
I have put an await keyword in front of the doses.where('userID', isEqualTo: Auth().uID).get(). This will allow the response to return and be assigned to the variable dose.
To read more about futures I would suggest going through https://api.flutter.dev/flutter/dart-async/Future-class.html.
I hope that helps!
This might work for you:
var dose =
await doses.where('userID', isEqualTo: Auth().uID).get();
var userData = dose.docs.first.data();
endController.text = userData['endDate'];
startController.text = userData['startDate'];
noPills = userData['noPills'];
doseController.text = userData['doseVal'];
doseRep = userData["doseRep"];

How to retrieve current user data from firebase?

I tried this way, but i'm getting an error.
The error:
The method 'data' isn't defined for the type 'CollectionReference'. (undefined_method at [myapp] android\app\lib\useracc.dart:32)
void getData() async{
User? user = await FirebaseAuth.instance.currentUser;
var vari =FirebaseFirestore.instance.collection("users");
setState (() {
name = vari.data()['firstname'];
}
);
}
Signup/Register Page
Future<User?> _register(String fname,String lname ,String email, String password) async{
FirebaseAuth _auth = FirebaseAuth.instance;
FirebaseFirestore _firestore = FirebaseFirestore.instance;
try {
UserCredential userCrendetial = await _auth.createUserWithEmailAndPassword(email: emailController.text, password: passwordController.text);
print("Account created Succesfull");
userCrendetial.user!.updateDisplayName(fname);
userCrendetial.user!.updateDisplayName(lname);
await _firestore.collection('users').doc(_auth.currentUser!.uid).set({
"firstname": fname,
"lastname" : lname,
"email": email,
"uid": _auth.currentUser!.uid,
});
return userCrendetial.user;
} catch (e) {
print(e);
return null;
}
}
This is the user account from where i want to fetch info:
Please help. I'm struck here a long time.
You should retrieve the currentUser document then access its data:
void getData() async{
var vari = await FirebaseFirestore.instance
.collection("users")
.doc(FirebaseAuth.instance.currentUser.uid)
.get();
setState (() {
name = vari.data()['firstname'];
});
}
if you've saved your user's details in firestore and its document id is the same as that of user ID (which is preferred for ease of access and control), then:
var vari =FirebaseFirestore.instance.collection("users").doc(user!.uid).get();
This gets the document of the user, and the type is DocumentSnapshot.
Map<String,dynamic> userData = vari as Map<String,dynamic>;
now userData is stored in form of Map. suppose you want to access their 'name', so the syntax now goes like userData['name'].
Similarly other fields can be accessed from variable. It's preferred to store userData in a Provider to access it's contents anywhere in your app.
Full code snippet
void getData() async{
User? user = await FirebaseAuth.instance.currentUser;
var vari =FirebaseFirestore.instance.collection("users").doc(user!.uid).get();
Map<String,dynamic> userData = vari as Map<String,dynamic>;
setState (() {
name = userData['firstname']; //or name = userData['name']
}
);
}

How do I get a query from another file to return a bool?

I am integrating the following system into my to-do app:
Every time the user opens the app, it should check whether the date stored in Cloud Firestore has been exceeded.
If this is the case, all To-Dos of the user should be reset to false.
This is the date in Cloud Firestore I’m looking for:
This function should check if the date has been exceeded:
Future<bool> checkTime() async{
DateTime now = DateTime.now();
var query = users.where('Startdatum', isLessThanOrEqualTo: now);
query = query.where('userID', isEqualTo: userID);
final querySnapshot = await query.get();
return querySnapshot.size > 0;
}
And this function should reset all To-Dos to false:
Future allFalse() async{
return await users.doc(userID).get().then((DocumentSnapshot doc) {
var updateMap = new Map();
var toDos = doc['Level'];
for (var item in toDos.keys) {
updateMap[item] = false;
}
doc.reference.update({'Level' : updateMap});
});
}
I created both functions in a separate file (database), as you can see here:
class DatabaseService {
String userID;
DatabaseService(this.userID);
final CollectionReference users =
FirebaseFirestore.instance.collection('users');
Future allFalse() async {
return await users.doc(userID).get().then((DocumentSnapshot doc) {
var updateMap = new Map();
var toDos = doc['Level'];
for (var item in toDos.keys) {
updateMap[item] = false;
}
doc.reference.update({'Level': updateMap});
});
}
Future<bool> checkTime() async {
DateTime now = DateTime.now();
var query = users.where('Startdatum', isLessThanOrEqualTo: now);
query = query.where('userID', isEqualTo: userID);
final querySnapshot = await query.get();
return querySnapshot.size > 0;
}
}
I create an if condition in in inite State that includes checkTime. If checkTime returns true, the Future returns allFalse, which sets all To-Dos to false.
class _UebersichtState extends State<Uebersicht> {
User? user;
late DatabaseService database;
Future<void> connect() async{
final FirebaseAuth auth = FirebaseAuth.instance;
UserCredential result = await auth.signInAnonymously();
user = result.user;
database = DatabaseService(user!.uid);
}
#override
void initState() {
// TODO: implement initState
super.initState();
connect();
Future.delayed(Duration(seconds: 3), () async{
if(await database.checkTime()) {
return await database.allFalse();}
else print('Still time left');
});
}
I used a delay because the connect () function has to be executed first, it initializes database.
When I start the app, no error appears, but the To-Dos are not reset either.
Today we have the 21. 12. 2021 and in Cloud Firestore is 14. 12. 21 deposited.
The function allFalse works, it resets the To-Dos all.
It must be the function checkTime, which does not return a bool in the if condition. I just replaced it with if (0 == 0) and that triggers allFalse.
Can someone help me?
This is just a guess, but I believe this is the problem:
query = query.where('userID', isEqualTo: userID);
The above line would only work if your document had a field userID and said field was equal to your UID, but from what I could gather, you identify the UID by the name of the documents, if that is the case, this should work?
Future<bool> checkTime() async {
CollectionReference users = FirebaseFirestore.instance.collection('users');
final now = DateTime.now();
final doc = await users.doc(userID).get();
final stufenzeit = (doc.data() as Map<String, dynamic>)['Stufenzeit'] as Map<String, dynamic>;
final storedDate = (stufenSetit['Startdatum'] as TimeStamp).toDate();
return now.compareTo(storedDate) > 0;
}
There's probably also a way to do it with queries, but I am not so well versed on those to be completely honest.

How can i save shared prefrence in list?

i have two class , in first class set sharedPrefrence like this :
[{"name":"alex","code":"12345"}]
my shared prefrence set method :
Future _shared() async {
final _customer = {
"name": _controller1.text,
"code": _controller2.text,
};
List<Map<String, dynamic>> customers = [];
customers.add(_customer);
final customerEncode = jsonEncode(customers);
SharedPreferences pref = await SharedPreferences.getInstance();
pref.setString("list_customer", customerEncode);
print(customerEncode);
}
and show this list in second class , i want when back to first class and enter name and code , they are add to previous list(keep later data) like this :
[{"name":"alex","code":"12345"},{"name":"john","code":"98765"}]
how can i do this ?
Create Customer Model:
class Customer{
Customer({this.name, this.code});
String name;
String code;
Customer.fromMap(json)
: name = json['name'].toString(),
code= json['code'].toString();
}
Then, create a method which adds into your SharedPreferences list:
addIntoList(Customer obj){
List<Customer> customersList = new List();
SharedPreferences pref = await SharedPreferences.getInstance();
// get list from SharedPreferences
var customers = pref.getString("list_customer");
var customersDecode = jsonDecode(customers);
// loop through your saved array and get them into customersList
customerDecode.forEach((val) {
customersList.add(Customer.fromMap(val));
});
// at last, add your parameter object
customersList.add(obj);
// save list to SharedPreferences
pref.setString("list_customer", jsonEncode(customersList));
}

flutter add value to list

i set object like this : {"name":"alex","code":"123"}
into sharedPrefrence Calss A:
var resBody = {};
resBody["name"] = name.text;
resBody["code"] = pass.text;
str = json.encode(resBody);
print(str);
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setString("list_customer", str);
and when get this sharedPrefrence in another class
add value of shared to the list Class B:
customer = (prefs.getString('list_customer'));
Map<String, dynamic> user = jsonDecode(customer);
_customer.nameFamily = user['name'];
_customer.code = user['code'];
_list.add(_customer);
and i want to know how can i set new value of shared into the previous list like this :
[{"name":"alex","code":"123"},{"name":"john","code":"128"}]
To store multiple customers, you need a List not Map.
Declare a List
List<Map<String, dynamic>> customers = [];
Add object(s) to the list
final customer = {
"name": name.text,
"code": pass.text,
};
customers.add(customer);
Stringfy (encode) customers list
final customersString = json.encode(customers);
Store encoded customers list
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setString("list_customer", customersString);
Let's say you store one customer, and now you need to store another.
we get customers list first, then we decode it
String customersString = await prefs.getString('list_customer');
final customers = json.decode(customersString);
Add the new object to the list (previous step #2)
customers.add({
"name": 'Amir',
"code": 'SWF2022',
});
Repeat step #3 and #4.
Good luck
Check example below
Future saveGetValues() async {
const key = 'list_customer';
var list = <Map<String, String>>[];
list.add(createValue('name1', 'code2'));
//save first time
save(key, list);
list = await getValue<List<Map<String, String>>>(key); //here your saved list
//add second value
list.add(createValue('name2', 'code2'));
save(key, list);
list = await getValue<List<Map<String, String>>>(key); //here your saved list with two items
}
Map<String, String> createValue(String name, String code) {
final resBody = <String, String>{};
resBody["name"] = name;
resBody["code"] = code;
return resBody;
}
Future save(String key, dynamic value) async {
final prefs = await SharedPreferences.getInstance();
prefs.setString(key, jsonEncode(value));
}
Future<T> getValue<T>(String key) async {
final prefs = await SharedPreferences.getInstance();
return json.decode(prefs.getString(key)) as T;
}